Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switch to server-side hashing for SignServer support #260

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 10 additions & 7 deletions docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -887,17 +887,20 @@ <h4 id="example-hashicorpvault">Signing with HashiCorp Vault</h4>

<h4 id="example-signserver">Signing with Keyfactor SignServer</h4>

<p><a href="https://www.signserver.org">SignServer</a> is an on-premises open source signing service developed by Keyfactor.
<p><a href="https://www.signserver.org">SignServer</a> is an on-premises (or cloud) open source signing service developed by Keyfactor.
SignServer supports various signing operations handled by signer workers. Jsign requires a
<a href="https://doc.primekey.com/signserver/signserver-reference/signserver-workers/signserver-signers/plain-signer">Plain Signer</a>
worker configured with the <code>CLIENTSIDEHASHING</code> or <code>ALLOW_CLIENTSIDEHASHING_OVERRIDE</code> properties
set to <code>true</code>, and the <code>SIGNATUREALGORITHM</code> property set to <code>NONEwithRSA</code> or
<code>NONEwithECDSA</code>.</p>
worker configured with the <code>CLIENTSIDEHASHING</code> property not set or set to <code>false</code> or
<code>ALLOW_CLIENTSIDEHASHING_OVERRIDE</code> property set to <code>true</code>, and the <code>SIGNATUREALGORITHM</code> property
set to a supported algorithm that ends in <code>withRSA</code> or <code>withECDSA</code>.
It is important that the hashing algorithm that is configured for the worker is consistent with the hashing
algorithm configured for Jsign, otherwise the signature verification will fail.</p>

<p>The authentication is performed by specifying the username/password or the TLS client certificate in the
<code>storepass</code> parameter. If the TLS client certificate is stored in a password protected keystore, the password
is specified in the <code>keypass</code> parameter. The <code>keystore</code> parameter references the URL of the
SignServer REST API. The <code>alias</code> parameter specifies the id or the name of the worker. </p>
<code>storepass</code> parameter if authentication is necessary. If the TLS client certificate is stored in
a password protected keystore, the password is specified in the <code>keypass</code> parameter.
The <code>keystore</code> parameter references the URL of the SignServer REST API. The <code>alias</code> parameter
specifies the id or the name of the worker. </p>

<p>Authenticating with a username and a password:</p>

Expand Down
15 changes: 9 additions & 6 deletions jsign-crypto/src/main/java/net/jsign/KeyStoreType.java
Original file line number Diff line number Diff line change
Expand Up @@ -561,14 +561,17 @@ Provider getProvider(KeyStoreBuilder params) {
},

/**
* Keyfactor SignServer. This keystore requires a Plain Signer worker configured to allow client-side hashing (with
* the properties <code>CLIENTSIDEHASHING</code> or <code>ALLOW_CLIENTSIDEHASHING_OVERRIDE</code> set to true), and
* the <code>SIGNATUREALGORITHM</code> property set to <code>NONEwithRSA</code> or <code>NONEwithECDSA</code>.
* Keyfactor SignServer. This keystore requires a Plain Signer worker configured to allow server-side hashing (with
* the property <code>CLIENTSIDEHASHING</code> not set or set to <code>false</code> or
* <code>ALLOW_CLIENTSIDEHASHING_OVERRIDE</code> set to <code>true</code>), and the <code>SIGNATUREALGORITHM</code>
* property set to a supported algorithm that ends in <code>withRSA</code> or <code>withECDSA</code>.
* It is important that the hashing algorithm that is configured for the worker is consistent with the hashing
* algorithm configured for Jsign, otherwise the signature verification will fail.
*
* <p>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 is
* specified in the keypass parameter. The keystore parameter references the URL of the SignServer REST API. The
* alias parameter specifies the id or the name of the worker.</p>
* storepass parameter if authentication is necessary. If the TLS client certificate is stored in a password
* protected keystore, the password is specified in the keypass parameter. The keystore parameter references
* the URL of the SignServer REST API. The alias parameter specifies the id or the name of the worker.</p>
*/
SIGNSERVER(false, false) {
@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,13 @@ public List<String> aliases() throws KeyStoreException {
public Certificate[] getCertificateChain(String alias) throws KeyStoreException {
if (!certificates.containsKey(alias)) {
try {
Map<String, ?> response = client.post("/rest/v1/workers/" + alias + "/process", "{\"data\":\"\"}");
Map<String, Object> request = new HashMap<>();
request.put("data", "");
Map<String, String> metadata = new HashMap<>();
metadata.put("USING_CLIENTSUPPLIED_HASH", "false");
request.put("metaData", metadata);

Map<String, ?> response = client.post("/rest/v1/workers/" + alias + "/process", JsonWriter.format(request));
String encodedCertificate = response.get("signerCertificate").toString();
byte[] certificateBytes = Base64.getDecoder().decode(encodedCertificate);
Certificate certificate = CertificateFactory.getInstance("X.509")
Expand All @@ -120,15 +126,11 @@ 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);

Map<String, Object> request = new HashMap<>();
request.put("data", Base64.getEncoder().encodeToString(data));
request.put("encoding", "BASE64");
Map<String, String> metadata = new HashMap<>();
metadata.put("USING_CLIENTSUPPLIED_HASH", "true");
metadata.put("CLIENTSIDE_HASHDIGESTALGORITHM", digestAlgorithm.id);
metadata.put("USING_CLIENTSUPPLIED_HASH", "false");
request.put("metaData", metadata);

try {
Expand Down
Loading