diff --git a/app/core/src/main/java/stirling/software/SPDF/controller/api/security/CertSignController.java b/app/core/src/main/java/stirling/software/SPDF/controller/api/security/CertSignController.java index 3b27492a6..893c9c54c 100644 --- a/app/core/src/main/java/stirling/software/SPDF/controller/api/security/CertSignController.java +++ b/app/core/src/main/java/stirling/software/SPDF/controller/api/security/CertSignController.java @@ -191,6 +191,12 @@ public class CertSignController { switch (certType) { case "PEM": + privateKeyFile = + validateFilePresent( + privateKeyFile, "PEM private key", "private key file is required"); + certFile = + validateFilePresent( + certFile, "PEM certificate", "certificate file is required"); ks = KeyStore.getInstance("JKS"); ks.load(null); PrivateKey privateKey = getPrivateKeyFromPEM(privateKeyFile.getBytes(), password); @@ -200,10 +206,16 @@ public class CertSignController { break; case "PKCS12": case "PFX": + p12File = + validateFilePresent( + p12File, "PKCS12 keystore", "PKCS12/PFX keystore file is required"); ks = KeyStore.getInstance("PKCS12"); ks.load(p12File.getInputStream(), password.toCharArray()); break; case "JKS": + jksfile = + validateFilePresent( + jksfile, "JKS keystore", "JKS keystore file is required"); ks = KeyStore.getInstance("JKS"); ks.load(jksfile.getInputStream(), password.toCharArray()); break; @@ -251,6 +263,17 @@ public class CertSignController { GeneralUtils.generateFilename(pdf.getOriginalFilename(), "_signed.pdf")); } + private MultipartFile validateFilePresent( + MultipartFile file, String argumentName, String errorDescription) { + if (file == null || file.isEmpty()) { + throw ExceptionUtils.createIllegalArgumentException( + "error.invalidArgument", + "Invalid argument: {0}", + argumentName + " - " + errorDescription); + } + return file; + } + private PrivateKey getPrivateKeyFromPEM(byte[] pemBytes, String password) throws IOException, OperatorCreationException, PKCSException { try (PEMParser pemParser = diff --git a/app/core/src/test/java/stirling/software/SPDF/controller/api/security/CertSignControllerTest.java b/app/core/src/test/java/stirling/software/SPDF/controller/api/security/CertSignControllerTest.java index c9f02cd28..5a5eff1f1 100644 --- a/app/core/src/test/java/stirling/software/SPDF/controller/api/security/CertSignControllerTest.java +++ b/app/core/src/test/java/stirling/software/SPDF/controller/api/security/CertSignControllerTest.java @@ -1,9 +1,10 @@ package stirling.software.SPDF.controller.api.security; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.when; +import static org.mockito.Mockito.lenient; import java.io.ByteArrayOutputStream; import java.io.InputStream; @@ -107,7 +108,8 @@ class CertSignControllerTest { derCertBytes = baos.toByteArray(); } - when(pdfDocumentFactory.load(any(MultipartFile.class))) + lenient() + .when(pdfDocumentFactory.load(any(MultipartFile.class))) .thenAnswer( invocation -> { MultipartFile file = invocation.getArgument(0); @@ -167,6 +169,31 @@ class CertSignControllerTest { assertTrue(response.getBody().length > 0); } + @Test + void testSignPdfWithMissingPkcs12FileThrowsError() { + MockMultipartFile pdfFile = + new MockMultipartFile( + "fileInput", "test.pdf", MediaType.APPLICATION_PDF_VALUE, pdfBytes); + + SignPDFWithCertRequest request = new SignPDFWithCertRequest(); + request.setFileInput(pdfFile); + request.setCertType("PFX"); + request.setPassword("password"); + request.setShowSignature(false); + request.setReason("test"); + request.setLocation("test"); + request.setName("tester"); + request.setPageNumber(1); + request.setShowLogo(false); + + IllegalArgumentException exception = + assertThrows( + IllegalArgumentException.class, + () -> certSignController.signPDFWithCert(request)); + + assertTrue(exception.getMessage().contains("PKCS12 keystore")); + } + @Test void testSignPdfWithJks() throws Exception { MockMultipartFile pdfFile =