Skip to content

Commit 2ecde87

Browse files
authored
Prepare support for multiple signing engines (#420)
1 parent 0526e04 commit 2ecde87

83 files changed

Lines changed: 2636 additions & 548 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

design-doc/3.1-signing-engines.md

Lines changed: 692 additions & 0 deletions
Large diffs are not rendered by default.

distribution/doc/release-notes/3.1.0.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,16 @@ runtime.
3030
`bin\jsignpdf.cmd` launchers (and `com.intoolswetrust.jsignpdf.Bootstrap`
3131
for runtime checks + JavaFX classifier selection) instead.
3232
- **`jsignpdf-3.1.0-SHA256SUMS.txt`** covers every release artifact.
33+
- **Pluggable signing engines (phase 1).** The signing backend is now
34+
selectable. JSignPdf ships the **OpenPDF** engine as the default, and
35+
its output is byte-for-byte identical to previous releases, so nothing
36+
changes by default. New `--list-engines` and `-eng` / `--engine` CLI
37+
options, plus an *Engine* selector in the JavaFX toolbar, let you pick
38+
the engine; the choice is stored in `advanced.properties`
39+
(`engine=openpdf`). Engines are discovered via `ServiceLoader` from
40+
`lib/`, so third-party engines can be dropped in. Additional engines
41+
(PDFBox, EU DSS / PAdES) are planned for a follow-up. See
42+
`design-doc/3.1-signing-engines.md`.
3343

3444
## Notes
3545

distribution/pom.xml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,17 @@
218218
<artifactId>jsignpdf</artifactId>
219219
<version>${project.version}</version>
220220
</dependency>
221+
<!--
222+
Bundled signing engines. The main jsignpdf jar compile-depends only on the engine API;
223+
the concrete engine implementations are pulled in here (runtime) so their jars land in
224+
lib/ and are discovered via ServiceLoader. Additional engines (PDFBox, DSS) are added
225+
here in phase 2.
226+
-->
227+
<dependency>
228+
<groupId>${project.groupId}</groupId>
229+
<artifactId>jsignpdf-engine-openpdf</artifactId>
230+
<version>${project.version}</version>
231+
</dependency>
221232
<dependency>
222233
<groupId>${project.groupId}</groupId>
223234
<artifactId>installcert</artifactId>

engines/api/pom.xml

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
2+
<modelVersion>4.0.0</modelVersion>
3+
4+
<artifactId>jsignpdf-engine-api</artifactId>
5+
<packaging>jar</packaging>
6+
<name>${project.artifactId}</name>
7+
<description>JSignPdf signing-engine SPI and shared signing model</description>
8+
9+
<parent>
10+
<groupId>com.github.kwart.jsign</groupId>
11+
<artifactId>jsignpdf-root</artifactId>
12+
<version>3.1.0-SNAPSHOT</version>
13+
<relativePath>../../pom.xml</relativePath>
14+
</parent>
15+
16+
<!--
17+
The engine API is the backend-neutral core: the SPI (SigningEngine / Capability / EngineConfig),
18+
the shared signing model (BasicSignerOptions, types, listeners) and the configuration / keystore
19+
utilities every engine relies on. It deliberately depends ONLY on BouncyCastle + commons (and
20+
the PKCS#11 helper); it must never depend on a signing backend (OpenPDF / PDFBox / DSS).
21+
-->
22+
<dependencies>
23+
<dependency>
24+
<groupId>org.bouncycastle</groupId>
25+
<artifactId>bcprov-jdk18on</artifactId>
26+
</dependency>
27+
<dependency>
28+
<groupId>org.bouncycastle</groupId>
29+
<artifactId>bcpkix-jdk18on</artifactId>
30+
</dependency>
31+
<dependency>
32+
<groupId>org.apache.commons</groupId>
33+
<artifactId>commons-lang3</artifactId>
34+
</dependency>
35+
<dependency>
36+
<groupId>commons-io</groupId>
37+
<artifactId>commons-io</artifactId>
38+
</dependency>
39+
<dependency>
40+
<groupId>com.github.kwart.jsign</groupId>
41+
<artifactId>jsign-pkcs11</artifactId>
42+
</dependency>
43+
</dependencies>
44+
</project>

jsignpdf/src/main/java/net/sf/jsignpdf/BasicSignerOptions.java renamed to engines/api/src/main/java/net/sf/jsignpdf/BasicSignerOptions.java

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
import net.sf.jsignpdf.utils.PropertyProvider;
1717
import net.sf.jsignpdf.utils.PropertyStoreFactory;
1818

19-
import org.apache.commons.cli.ParseException;
2019
import org.apache.commons.lang3.StringUtils;
2120
import org.bouncycastle.crypto.CryptoException;
2221

@@ -103,6 +102,11 @@ public class BasicSignerOptions {
103102

104103
private String[] cmdLine;
105104

105+
// Signing engine id. Transient per-invocation override (set by the CLI --engine flag); not
106+
// persisted in config.properties. When null, the dispatcher falls back to the engine selected in
107+
// advanced.properties (see AppConfig#defaultEngineId()).
108+
private String engine;
109+
106110
/**
107111
* Loads options from PropertyProvider
108112
*/
@@ -1221,6 +1225,20 @@ public Proxy createProxy() {
12211225
return tmpResult;
12221226
}
12231227

1228+
/**
1229+
* @return the signing-engine id override (CLI {@code --engine}), or {@code null} when unset
1230+
*/
1231+
public String getEngine() {
1232+
return engine;
1233+
}
1234+
1235+
/**
1236+
* @param engine the signing-engine id override to set (CLI {@code --engine})
1237+
*/
1238+
public void setEngine(final String engine) {
1239+
this.engine = engine;
1240+
}
1241+
12241242
protected String[] getCmdLine() {
12251243
return cmdLine;
12261244
}
@@ -1297,6 +1315,7 @@ public BasicSignerOptions createCopy() {
12971315
copy.setProxyType(getProxyType());
12981316
copy.setProxyHost(getProxyHost());
12991317
copy.setProxyPort(getProxyPort());
1318+
copy.setEngine(getEngine());
13001319
return copy;
13011320
}
13021321

jsignpdf/src/main/java/net/sf/jsignpdf/Constants.java renamed to engines/api/src/main/java/net/sf/jsignpdf/Constants.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,12 @@ public class Constants {
246246
public static final String ARG_LIST_KEYS = "lk";
247247
public static final String ARG_LIST_KEYS_LONG = "list-keys";
248248

249+
public static final String ARG_ENGINE = "eng";
250+
public static final String ARG_ENGINE_LONG = "engine";
251+
252+
public static final String ARG_LIST_ENGINES = "le";
253+
public static final String ARG_LIST_ENGINES_LONG = "list-engines";
254+
249255
public static final String ARG_KS_TYPE_LONG = "keystore-type";
250256
public static final String ARG_KS_TYPE = "kst";
251257

jsignpdf/src/main/java/net/sf/jsignpdf/JSignEncryptor.java renamed to engines/api/src/main/java/net/sf/jsignpdf/JSignEncryptor.java

File renamed without changes.

jsignpdf/src/main/java/net/sf/jsignpdf/PrivateKeyInfo.java renamed to engines/api/src/main/java/net/sf/jsignpdf/PrivateKeyInfo.java

File renamed without changes.

jsignpdf/src/main/java/net/sf/jsignpdf/SignResultListener.java renamed to engines/api/src/main/java/net/sf/jsignpdf/SignResultListener.java

File renamed without changes.
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package net.sf.jsignpdf.engine;
2+
3+
import net.sf.jsignpdf.utils.AdvancedConfig;
4+
5+
/**
6+
* {@link EngineConfig} backed by {@link AdvancedConfig}, resolving engine-relative keys under a fixed
7+
* {@code engine.<id>.} prefix.
8+
*
9+
* @author Josef Cacek
10+
*/
11+
public final class AdvancedEngineConfig implements EngineConfig {
12+
13+
private final AdvancedConfig cfg;
14+
private final String prefix;
15+
16+
/**
17+
* @param cfg the backing advanced configuration
18+
* @param prefix the {@code engine.<id>.} key prefix (including the trailing dot)
19+
*/
20+
public AdvancedEngineConfig(AdvancedConfig cfg, String prefix) {
21+
this.cfg = cfg;
22+
this.prefix = prefix;
23+
}
24+
25+
@Override
26+
public String getString(String key) {
27+
return cfg.getProperty(prefix + key);
28+
}
29+
30+
@Override
31+
public String getString(String key, String fallback) {
32+
return cfg.getProperty(prefix + key, fallback);
33+
}
34+
35+
@Override
36+
public boolean getBoolean(String key, boolean fallback) {
37+
return cfg.getAsBool(prefix + key, fallback);
38+
}
39+
40+
@Override
41+
public int getInt(String key, int fallback) {
42+
return cfg.getAsInt(prefix + key, fallback);
43+
}
44+
}

0 commit comments

Comments
 (0)