diff --git a/docs/index.html b/docs/index.html
index 544961e9..9020f7ef 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -890,9 +890,12 @@
Signing with Keyfactor SignServer
SignServer is a cloud/on-premises open source signing service developed by
Keyfactor. SignServer supports various signing operations handled by signer workers. Jsign requires a
Plain Signer
-worker configured with the CLIENTSIDEHASHING
or ALLOW_CLIENTSIDEHASHING_OVERRIDE
properties
-set to true
, and the SIGNATUREALGORITHM
property set to NONEwithRSA
or
-NONEwithECDSA
.
+worker, preferably configured with the CLIENTSIDEHASHING
or ALLOW_CLIENTSIDEHASHING_OVERRIDE
+properties set to true
, and the SIGNATUREALGORITHM
property set to NONEwithRSA
or
+NONEwithECDSA
. The worker may be configured with server-side hashing (i.e. with CLIENTSIDEHASHING
+and ALLOW_CLIENTSIDEHASHING_OVERRIDE
set to false
, and a proper
+SIGNATUREALGORITHM
set), in this case the worker name or id in the alias has to be suffixed with
+|serverside
.
If necessary the authentication is performed by specifying the username/password or the TLS client certificate in the
storepass
parameter. If the TLS client certificate is stored in a password protected keystore, the password
@@ -920,6 +923,16 @@
Signing with Keyfactor SignServer
application.exe
+Using server-side hashing, the digest algorithm must match the one configured for the worker:
+
+
+ jsign --storetype SIGNSERVER \
+ --keystore https://example.com/signserver \
+ --alias "test|serverside" \
+ --alg SHA-512 \
+ application.exe
+
+
Signing with Oracle Cloud Key Management Service
diff --git a/jsign-crypto/src/main/java/net/jsign/KeyStoreType.java b/jsign-crypto/src/main/java/net/jsign/KeyStoreType.java
index f2b12a00..40b4d693 100644
--- a/jsign-crypto/src/main/java/net/jsign/KeyStoreType.java
+++ b/jsign-crypto/src/main/java/net/jsign/KeyStoreType.java
@@ -561,9 +561,12 @@ Provider getProvider(KeyStoreBuilder params) {
},
/**
- * Keyfactor SignServer. This keystore requires a Plain Signer worker configured to allow client-side hashing (with
- * the properties CLIENTSIDEHASHING
or ALLOW_CLIENTSIDEHASHING_OVERRIDE
set to true), and
- * the SIGNATUREALGORITHM
property set to NONEwithRSA
or NONEwithECDSA
.
+ * Keyfactor SignServer. This keystore requires a Plain Signer worker, preferably configured to allow client-side
+ * hashing (with the properties CLIENTSIDEHASHING
or ALLOW_CLIENTSIDEHASHING_OVERRIDE
set
+ * to true), and the SIGNATUREALGORITHM
property set to NONEwithRSA
or NONEwithECDSA
.
+ * The worker may be configured with server-side hashing (i.e. with CLIENTSIDEHASHING
and
+ * ALLOW_CLIENTSIDEHASHING_OVERRIDE
set to false
, and a proper SIGNATUREALGORITHM
+ * set), in this case the worker name or id in the alias has to be suffixed with |serverside
.
*
* If necessary the authentication is performed by specifying the username/password or the TLS client certificate
* in the storepass parameter. If the TLS client certificate is stored in a password protected keystore, the password
diff --git a/jsign-crypto/src/main/java/net/jsign/jca/SignServerSigningService.java b/jsign-crypto/src/main/java/net/jsign/jca/SignServerSigningService.java
index fc39f87a..188dd232 100644
--- a/jsign-crypto/src/main/java/net/jsign/jca/SignServerSigningService.java
+++ b/jsign-crypto/src/main/java/net/jsign/jca/SignServerSigningService.java
@@ -94,7 +94,29 @@ public List aliases() throws KeyStoreException {
public Certificate[] getCertificateChain(String alias) throws KeyStoreException {
if (!certificates.containsKey(alias)) {
try {
- Map response = client.post("/rest/v1/workers/" + alias + "/process", "{\"data\":\"\"}");
+ String worker = alias;
+ boolean serverside = false;
+ if (worker.endsWith("|serverside")) {
+ worker = worker.substring(0, worker.length() - 11);
+ serverside = true;
+ }
+
+ Map request = new HashMap<>();
+ if (serverside) {
+ request.put("data", "");
+ Map metadata = new HashMap<>();
+ metadata.put("USING_CLIENTSUPPLIED_HASH", "false");
+ request.put("metaData", metadata);
+ } else {
+ request.put("data", "47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=");
+ request.put("encoding", "BASE64");
+ Map metadata = new HashMap<>();
+ metadata.put("USING_CLIENTSUPPLIED_HASH", "true");
+ metadata.put("CLIENTSIDE_HASHDIGESTALGORITHM", "SHA-256");
+ request.put("metaData", metadata);
+ }
+
+ Map response = client.post("/rest/v1/workers/" + worker + "/process", JsonWriter.format(request));
String encodedCertificate = response.get("signerCertificate").toString();
byte[] certificateBytes = Base64.getDecoder().decode(encodedCertificate);
Certificate certificate = CertificateFactory.getInstance("X.509")
@@ -120,19 +142,32 @@ public SigningServicePrivateKey getPrivateKey(String alias, char[] password) thr
@Override
public byte[] sign(SigningServicePrivateKey privateKey, String algorithm, byte[] data) throws GeneralSecurityException {
- DigestAlgorithm digestAlgorithm = DigestAlgorithm.of(algorithm.substring(0, algorithm.toLowerCase().indexOf("with")));
- data = digestAlgorithm.getMessageDigest().digest(data);
+ String worker = privateKey.getId();
+ boolean serverside = false;
+ if (worker.endsWith("|serverside")) {
+ worker = worker.substring(0, worker.length() - 11);
+ serverside = true;
+ }
Map request = new HashMap<>();
- request.put("data", Base64.getEncoder().encodeToString(data));
+ if (serverside) {
+ request.put("data", Base64.getEncoder().encodeToString(data));
+ Map metadata = new HashMap<>();
+ metadata.put("USING_CLIENTSUPPLIED_HASH", "false");
+ request.put("metaData", metadata);
+ } else {
+ DigestAlgorithm digestAlgorithm = DigestAlgorithm.of(algorithm.substring(0, algorithm.toLowerCase().indexOf("with")));
+ data = digestAlgorithm.getMessageDigest().digest(data);
+ request.put("data", Base64.getEncoder().encodeToString(data));
+ Map metadata = new HashMap<>();
+ metadata.put("USING_CLIENTSUPPLIED_HASH", "true");
+ metadata.put("CLIENTSIDE_HASHDIGESTALGORITHM", digestAlgorithm.id);
+ request.put("metaData", metadata);
+ }
request.put("encoding", "BASE64");
- Map metadata = new HashMap<>();
- metadata.put("USING_CLIENTSUPPLIED_HASH", "true");
- metadata.put("CLIENTSIDE_HASHDIGESTALGORITHM", digestAlgorithm.id);
- request.put("metaData", metadata);
try {
- Map response = client.post("/rest/v1/workers/" + privateKey.getId() + "/process", JsonWriter.format(request));
+ Map response = client.post("/rest/v1/workers/" + worker + "/process", JsonWriter.format(request));
return Base64.getDecoder().decode((String) response.get("data"));
} catch (IOException e) {
throw new GeneralSecurityException(e);
diff --git a/jsign/src/deb/data/usr/share/man/man1/jsign.1 b/jsign/src/deb/data/usr/share/man/man1/jsign.1
index 5c6e981d..eb59e6f8 100644
--- a/jsign/src/deb/data/usr/share/man/man1/jsign.1
+++ b/jsign/src/deb/data/usr/share/man/man1/jsign.1
@@ -512,13 +512,14 @@ jsign --storetype HASHICORPVAULT \\
.TP
-
Signing with Keyfactor SignServer:
SignServer is a cloud/on-premises open source signing service developed by Keyfactor. SignServer supports various
-signing operations handled by signer workers. Jsign requires a Plain Signer worker configured with the CLIENTSIDEHASHING
-or ALLOW_CLIENTSIDEHASHING_OVERRIDE properties set to true, and the SIGNATUREALGORITHM property set to NONEwithRSA or
-NONEwithECDSA.
+signing operations handled by signer workers. Jsign requires a Plain Signer worker, preferably configured with the
+CLIENTSIDEHASHING or ALLOW_CLIENTSIDEHASHING_OVERRIDE properties set to true, and the SIGNATUREALGORITHM property
+set to NONEwithRSA or NONEwithECDSA. The worker may be configured with server-side hashing (i.e. with CLIENTSIDEHASHING
+and ALLOW_CLIENTSIDEHASHING_OVERRIDE set to false, and a proper SIGNATUREALGORITHM set), in this case the worker name
+or id in the alias has to be suffixed with '|serverside'.
If necessary the authentication is performed by specifying the username/password or the TLS client certificate in the
storepass parameter. If the TLS client certificate is stored in a password protected keystore, the password
@@ -542,6 +543,16 @@ jsign --storetype SIGNSERVER \
--alias test \
application.exe
+Using server-side hashing, the digest algorithm must match the one configured for the worker:
+
+jsign --storetype SIGNSERVER \
+ --keystore https://example.com/signserver \
+ --alias 'test|serverside' \
+ --alg SHA-512 \
+ application.exe
+
+
+.TP
Signing with Oracle Cloud Key Management Service