diff --git a/.gitignore b/.gitignore
index 21e7defe1..5b6c02c22 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,7 +9,9 @@ buildNumber.properties
.mvn/timing.properties
# https://github.com/takari/maven-wrapper#usage-without-binary-jar
.mvn/wrapper/maven-wrapper.jar
-.idea/
+.idea/workspace.xml
+.idea/usage.statistics.xml
+.idea/shelf
whitelabel.iml
# IDE - It's up to developer to decide, we don't want to force configuration
@@ -28,3 +30,5 @@ secret
.autogram
/fakeTokenDriver
+
+/cache
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
new file mode 100644
index 000000000..18548bc5c
--- /dev/null
+++ b/.idea/compiler.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.run/Main.run.xml b/.run/Main.run.xml
index 705017daa..172ac9383 100644
--- a/.run/Main.run.xml
+++ b/.run/Main.run.xml
@@ -4,8 +4,7 @@
-
-
+
@@ -16,4 +15,21 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 94ca6ad8a..10e98371c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -193,11 +193,16 @@
3.11.0
- ${java.version}
true
${jlink.jdk.path}${file.separator}bin${file.separator}javac
-
- 17
+
+ ${java.version}
+
+ --add-exports
+ jdk.crypto.cryptoki/sun.security.pkcs11.wrapper=ALL-UNNAMED
+ --add-modules
+ jdk.crypto.cryptoki
+
diff --git a/src/main/java/digital/slovensko/autogram/core/Autogram.java b/src/main/java/digital/slovensko/autogram/core/Autogram.java
index c4165c24f..5e9ce8378 100644
--- a/src/main/java/digital/slovensko/autogram/core/Autogram.java
+++ b/src/main/java/digital/slovensko/autogram/core/Autogram.java
@@ -1,10 +1,6 @@
package digital.slovensko.autogram.core;
-import digital.slovensko.autogram.core.errors.AutogramException;
-import digital.slovensko.autogram.core.errors.BatchConflictException;
-import digital.slovensko.autogram.core.errors.BatchNotStartedException;
-import digital.slovensko.autogram.core.errors.ResponseNetworkErrorException;
-import digital.slovensko.autogram.core.errors.UnrecognizedException;
+import digital.slovensko.autogram.core.errors.*;
import digital.slovensko.autogram.core.visualization.DocumentVisualizationBuilder;
import digital.slovensko.autogram.core.visualization.UnsupportedVisualization;
import digital.slovensko.autogram.drivers.TokenDriver;
@@ -103,12 +99,14 @@ public void sign(SigningJob job, SigningKey signingKey) {
try {
job.signWithKeyAndRespond(signingKey);
ui.onUIThreadDo(() -> ui.onSigningSuccess(job));
+ } catch (ResponseNetworkErrorException e) {
+ onSigningFailed(e, job);
+ } catch (AutogramException e) {
+ onSigningFailed(e);
} catch (DSSException e) {
onSigningFailed(AutogramException.createFromDSSException(e));
} catch (IllegalArgumentException e) {
onSigningFailed(AutogramException.createFromIllegalArgumentException(e));
- } catch (ResponseNetworkErrorException e) {
- onSigningFailed(e, job);
} catch (Exception e) {
onSigningFailed(new UnrecognizedException(e));
}
@@ -145,7 +143,15 @@ public void batchSign(SigningJob job, String batchId) {
batch.addJob(batchId);
ui.onWorkThreadDo(() -> {
- ui.signBatch(job, batch.getSigningKey());
+ try {
+ ui.signBatch(job, batch.getSigningKey());
+ } catch (KeyPinDifferentFromTokenPinException e) {
+ ui.onUIThreadDo(() -> {
+ ui.cancelBatch(batch);
+ });
+
+ throw e;
+ }
});
}
diff --git a/src/main/java/digital/slovensko/autogram/core/ResponderInBatch.java b/src/main/java/digital/slovensko/autogram/core/ResponderInBatch.java
index 74904276d..b6ad9ad34 100644
--- a/src/main/java/digital/slovensko/autogram/core/ResponderInBatch.java
+++ b/src/main/java/digital/slovensko/autogram/core/ResponderInBatch.java
@@ -18,6 +18,9 @@ public void onDocumentSigned(SignedDocument signedDocument) {
public void onDocumentSignFailed(AutogramException error) {
batch.onJobFailure();
+ if (!error.batchCanContinue())
+ batch.end();
+
responder.onDocumentSignFailed(error);
}
}
diff --git a/src/main/java/digital/slovensko/autogram/core/errors/AutogramException.java b/src/main/java/digital/slovensko/autogram/core/errors/AutogramException.java
index 7686c484e..c268aa6de 100644
--- a/src/main/java/digital/slovensko/autogram/core/errors/AutogramException.java
+++ b/src/main/java/digital/slovensko/autogram/core/errors/AutogramException.java
@@ -37,6 +37,8 @@ public String getDescription() {
public static AutogramException createFromDSSException(DSSException e) {
for (Throwable cause = e; cause != null && cause.getCause() != cause; cause = cause.getCause()) {
if (cause.getMessage() != null) {
+ if (cause instanceof KeyPinDifferentFromTokenPinException)
+ return (KeyPinDifferentFromTokenPinException) cause;
if (cause instanceof java.security.ProviderException && cause.getMessage().contains("slotListIndex is 0 but token only has 0 slots")) {
return new InitializationFailedException();
} else if (cause.getMessage().equals("CKR_FUNCTION_CANCELED")) {
@@ -67,4 +69,8 @@ public static AutogramException createFromIllegalArgumentException(IllegalArgume
return new UnrecognizedException(e);
}
+
+ public boolean batchCanContinue() {
+ return true;
+ }
}
diff --git a/src/main/java/digital/slovensko/autogram/core/errors/KeyPinDifferentFromTokenPinException.java b/src/main/java/digital/slovensko/autogram/core/errors/KeyPinDifferentFromTokenPinException.java
new file mode 100644
index 000000000..f4d8bd036
--- /dev/null
+++ b/src/main/java/digital/slovensko/autogram/core/errors/KeyPinDifferentFromTokenPinException.java
@@ -0,0 +1,12 @@
+package digital.slovensko.autogram.core.errors;
+
+public class KeyPinDifferentFromTokenPinException extends AutogramException {
+ public KeyPinDifferentFromTokenPinException(Throwable e) {
+ super("Nepodporovaný PIN certifikátu", "PIN podpisového certifikátu je iný než PIN úložiska certifikátov. Ďalšie podpisovanie môže viesť k zablokovaniu karty!", "Použitý certifikát má nastavený atribút CKA_ALWAYS_AUTHENTICATE a jeho PIN je iný než PIN úložiska certifikátov. Toto zatiaľ nepodporujeme. Kontaktujte nás, prosím, na podpora@slovensko.digital", e);
+ }
+
+ @Override
+ public boolean batchCanContinue() {
+ return false;
+ }
+}
diff --git a/src/main/java/digital/slovensko/autogram/drivers/NativePkcs11SignatureToken.java b/src/main/java/digital/slovensko/autogram/drivers/NativePkcs11SignatureToken.java
new file mode 100644
index 000000000..22880a2d7
--- /dev/null
+++ b/src/main/java/digital/slovensko/autogram/drivers/NativePkcs11SignatureToken.java
@@ -0,0 +1,173 @@
+package digital.slovensko.autogram.drivers;
+
+import digital.slovensko.autogram.core.errors.AutogramException;
+import digital.slovensko.autogram.core.errors.KeyPinDifferentFromTokenPinException;
+import eu.europa.esig.dss.enumerations.SignatureAlgorithm;
+import eu.europa.esig.dss.model.DSSException;
+import eu.europa.esig.dss.model.SignatureValue;
+import eu.europa.esig.dss.model.ToBeSigned;
+import eu.europa.esig.dss.token.DSSPrivateKeyEntry;
+import eu.europa.esig.dss.token.KSPrivateKeyEntry;
+import eu.europa.esig.dss.token.Pkcs11SignatureToken;
+import eu.europa.esig.dss.token.PrefilledPasswordCallback;
+import sun.security.pkcs11.wrapper.CK_ATTRIBUTE;
+import sun.security.pkcs11.wrapper.PKCS11;
+import sun.security.pkcs11.wrapper.PKCS11Constants;
+import sun.security.pkcs11.wrapper.PKCS11Exception;
+
+import java.lang.reflect.Field;
+import java.security.GeneralSecurityException;
+import java.security.PrivateKey;
+import java.security.Signature;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.Objects;
+
+public class NativePkcs11SignatureToken extends Pkcs11SignatureToken {
+ private static final long CKU_CONTEXT_SPECIFIC = 2L;
+
+ private final PrefilledPasswordCallback prefilledPasswordCallback;
+ private final boolean shouldProvidePasswordForCkaAA;
+
+ public NativePkcs11SignatureToken(String pkcsPath, PrefilledPasswordCallback prefilledPasswordCallback, int slotIndex, boolean shouldProvidePasswordForCkaAA) {
+ super(pkcsPath, prefilledPasswordCallback, -1, slotIndex, null);
+
+ this.prefilledPasswordCallback = prefilledPasswordCallback;
+ this.shouldProvidePasswordForCkaAA = shouldProvidePasswordForCkaAA;
+ }
+
+ private byte[] sign(final byte[] bytes, final String javaSignatureAlgorithm, final AlgorithmParameterSpec param, final DSSPrivateKeyEntry keyEntry) throws GeneralSecurityException {
+ if (!(keyEntry instanceof KSPrivateKeyEntry)) {
+ throw new IllegalArgumentException("Only KSPrivateKeyEntry are supported");
+ }
+
+ final Signature signature = getSignatureInstance(javaSignatureAlgorithm);
+ if (param != null) {
+ signature.setParameter(param);
+ }
+ var pk = ((KSPrivateKeyEntry) keyEntry).getPrivateKey();
+
+ signature.initSign(pk);
+ runContextSpecificLoginIfNeeded(signature, pk);
+ signature.update(bytes);
+ return signature.sign();
+ }
+
+ private void runContextSpecificLoginIfNeeded(Signature signature, PrivateKey pk) throws GeneralSecurityException {
+ try {
+ // TODO cache & short-circuit
+ var p11 = getP11(signature);
+ var sessionId = getSessionId(signature);
+ var keyID = getKeyID(pk);
+ var attrs = new CK_ATTRIBUTE[]{new CK_ATTRIBUTE(PKCS11Constants.CKA_ALWAYS_AUTHENTICATE)};
+
+ p11.C_GetAttributeValue(sessionId, keyID, attrs);
+ if (shouldProvidePasswordForCkaAA && isAlwaysAuthenticate(attrs))
+ p11.C_Login(sessionId, CKU_CONTEXT_SPECIFIC, prefilledPasswordCallback.getPassword());
+
+ } catch (PKCS11Exception e) {
+ if (e.getMessage().equals("CKR_PIN_INCORRECT"))
+ throw new KeyPinDifferentFromTokenPinException(e);
+
+ throw new GeneralSecurityException(e);
+ }
+ }
+
+ private static boolean isAlwaysAuthenticate(CK_ATTRIBUTE[] attrs) {
+ var result = attrs[0].pValue;
+ if (result instanceof byte[]) {
+ return ((byte[]) result)[0] == 1;
+ } else {
+ return false; // CKA_ALWAYS_AUTHENTICATE not found
+ }
+ }
+
+ private static long getKeyID(PrivateKey pk) {
+ try {
+ var keyIDHolderField = pk.getClass().getSuperclass().getDeclaredField("keyIDHolder");
+ keyIDHolderField.setAccessible(true);
+ var keyIDHolder = keyIDHolderField.get(pk);
+
+ var keyIDField = keyIDHolder.getClass().getDeclaredField("keyID");
+ keyIDField.setAccessible(true);
+
+ return (long) keyIDField.get(keyIDHolder);
+ } catch (IllegalAccessException | NoSuchFieldException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static long getSessionId(Signature signature) {
+ try {
+ Field sigSpiField = signature.getClass().getDeclaredField("sigSpi");
+ sigSpiField.setAccessible(true);
+ var sigSpi = sigSpiField.get(signature);
+
+ var sessionField = sigSpi.getClass().getDeclaredField("session");
+ sessionField.setAccessible(true);
+ var session = sessionField.get(sigSpi);
+
+ var idField = session.getClass().getDeclaredField("id");
+ idField.setAccessible(true);
+
+ return (long) idField.get(session);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static PKCS11 getP11(Signature signature) {
+ try {
+ Field sigSpiField = signature.getClass().getDeclaredField("sigSpi");
+ sigSpiField.setAccessible(true);
+ var sigSpi = sigSpiField.get(signature);
+
+ var tokenField = sigSpi.getClass().getDeclaredField("token");
+ tokenField.setAccessible(true);
+ var token = tokenField.get(sigSpi);
+
+ var p11Field = token.getClass().getDeclaredField("p11");
+ p11Field.setAccessible(true);
+ var p11 = p11Field.get(token);
+
+ return (PKCS11) p11;
+ } catch (NoSuchFieldException | IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ // copy & paste just to call overridden private sign method
+ @Override
+ public SignatureValue sign(ToBeSigned toBeSigned, SignatureAlgorithm signatureAlgorithm, DSSPrivateKeyEntry keyEntry) throws DSSException {
+ assertEncryptionAlgorithmValid(signatureAlgorithm, keyEntry);
+
+ final String javaSignatureAlgorithm = signatureAlgorithm.getJCEId();
+ final byte[] bytes = toBeSigned.getBytes();
+ AlgorithmParameterSpec param = null;
+ if (signatureAlgorithm.getMaskGenerationFunction() != null) {
+ param = createPSSParam(signatureAlgorithm.getDigestAlgorithm());
+ }
+
+ try {
+ final byte[] signatureValue = sign(bytes, javaSignatureAlgorithm, param, keyEntry);
+ SignatureValue value = new SignatureValue();
+ value.setAlgorithm(signatureAlgorithm);
+ value.setValue(signatureValue);
+ return value;
+ } catch (AutogramException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new DSSException(String.format("Unable to sign : %s", e.getMessage()), e);
+ }
+ }
+
+ // copy & paste
+ private void assertEncryptionAlgorithmValid(SignatureAlgorithm signatureAlgorithm, DSSPrivateKeyEntry keyEntry) {
+ Objects.requireNonNull(signatureAlgorithm, "SignatureAlgorithm shall be provided.");
+ Objects.requireNonNull(signatureAlgorithm.getEncryptionAlgorithm(), "EncryptionAlgorithm shall be provided within the SignatureAlgorithm.");
+ Objects.requireNonNull(keyEntry, "keyEntry shall be provided.");
+ if (!signatureAlgorithm.getEncryptionAlgorithm().isEquivalent(keyEntry.getEncryptionAlgorithm())) {
+ throw new IllegalArgumentException(String.format("The provided SignatureAlgorithm '%s' cannot be used to sign with " +
+ "the token's implied EncryptionAlgorithm '%s'", signatureAlgorithm.getName(), keyEntry.getEncryptionAlgorithm().getName()));
+ }
+ }
+}
diff --git a/src/main/java/digital/slovensko/autogram/drivers/PKCS11TokenDriver.java b/src/main/java/digital/slovensko/autogram/drivers/PKCS11TokenDriver.java
index add8d3f53..da83cdf36 100644
--- a/src/main/java/digital/slovensko/autogram/drivers/PKCS11TokenDriver.java
+++ b/src/main/java/digital/slovensko/autogram/drivers/PKCS11TokenDriver.java
@@ -1,7 +1,6 @@
package digital.slovensko.autogram.drivers;
import eu.europa.esig.dss.token.AbstractKeyStoreTokenConnection;
-import eu.europa.esig.dss.token.Pkcs11SignatureToken;
import eu.europa.esig.dss.token.PrefilledPasswordCallback;
import java.nio.file.Path;
@@ -13,7 +12,8 @@ public PKCS11TokenDriver(String name, Path path, boolean needsPassword, String s
}
@Override
- public AbstractKeyStoreTokenConnection createTokenWithPassword(Integer slotId, char[] password) {
- return new Pkcs11SignatureToken(getPath().toString(), new PrefilledPasswordCallback(new KeyStore.PasswordProtection(password)), -1, slotId, null);
+ public AbstractKeyStoreTokenConnection createTokenWithPassword(Integer slotIndex, char[] password) {
+ // TODO: shouldProvidePasswordForCkaAA happens to correlate with needsPassword() for now, because eID is different. Might be changed in the future.
+ return new NativePkcs11SignatureToken(getPath().toString(), new PrefilledPasswordCallback(new KeyStore.PasswordProtection(password)), slotIndex, needsPassword());
}
}
diff --git a/src/main/java/digital/slovensko/autogram/server/dto/ErrorResponse.java b/src/main/java/digital/slovensko/autogram/server/dto/ErrorResponse.java
index f3e3e654f..e2b91105d 100644
--- a/src/main/java/digital/slovensko/autogram/server/dto/ErrorResponse.java
+++ b/src/main/java/digital/slovensko/autogram/server/dto/ErrorResponse.java
@@ -48,6 +48,7 @@ public static ErrorResponse buildFromException(Exception e) {
case "BatchNotStartedException" -> new ErrorResponse(400, "BATCH_NOT_STARTED", (AutogramException) e);
case "BatchInvalidIdException" -> new ErrorResponse(404, "BATCH_NOT_FOUND", (AutogramException) e);
case "BatchConflictException" -> new ErrorResponse(400, "BATCH_CONFLICT", (AutogramException) e);
+ case "KeyPinDifferentFromTokenPin" -> new ErrorResponse(400, "CARD_NOT_SUPPORTED", (AutogramException) e);
default -> new ErrorResponse(500, "INTERNAL_ERROR", "Unexpected exception signing document", e.getMessage());
};
}
diff --git a/src/main/java/digital/slovensko/autogram/ui/BatchGuiFileResponder.java b/src/main/java/digital/slovensko/autogram/ui/BatchGuiFileResponder.java
index cae703658..948994e58 100644
--- a/src/main/java/digital/slovensko/autogram/ui/BatchGuiFileResponder.java
+++ b/src/main/java/digital/slovensko/autogram/ui/BatchGuiFileResponder.java
@@ -63,6 +63,7 @@ public void onBatchStartSuccess(Batch batch) {
autogram.batchSign(job, batch.getBatchId());
} catch (AutogramException e) {
autogram.onSigningFailed(e);
+
break;
}
}
diff --git a/src/main/java/digital/slovensko/autogram/ui/cli/CliUI.java b/src/main/java/digital/slovensko/autogram/ui/cli/CliUI.java
index b142d940e..db27eb71c 100644
--- a/src/main/java/digital/slovensko/autogram/ui/cli/CliUI.java
+++ b/src/main/java/digital/slovensko/autogram/ui/cli/CliUI.java
@@ -14,27 +14,7 @@
import digital.slovensko.autogram.core.SigningKey;
import digital.slovensko.autogram.core.Updater;
import digital.slovensko.autogram.core.ValidationReports;
-import digital.slovensko.autogram.core.errors.AutogramException;
-import digital.slovensko.autogram.core.errors.FunctionCanceledException;
-import digital.slovensko.autogram.core.errors.InitializationFailedException;
-import digital.slovensko.autogram.core.errors.NoDriversDetectedException;
-import digital.slovensko.autogram.core.errors.NoKeysDetectedException;
-import digital.slovensko.autogram.core.errors.PDFAComplianceException;
-import digital.slovensko.autogram.core.errors.PDFSignatureLevelIsNotValidException;
-import digital.slovensko.autogram.core.errors.PINIncorrectException;
-import digital.slovensko.autogram.core.errors.PINLockedException;
-import digital.slovensko.autogram.core.errors.SigningCanceledByUserException;
-import digital.slovensko.autogram.core.errors.SigningWithExpiredCertificateException;
-import digital.slovensko.autogram.core.errors.SlotIdIsNotANumberException;
-import digital.slovensko.autogram.core.errors.SourceAndTargetTypeMismatchException;
-import digital.slovensko.autogram.core.errors.SourceDoesNotExistException;
-import digital.slovensko.autogram.core.errors.SourceNotDefindedException;
-import digital.slovensko.autogram.core.errors.TargetAlreadyExistsException;
-import digital.slovensko.autogram.core.errors.TargetDirectoryDoesNotExistException;
-import digital.slovensko.autogram.core.errors.TokenDriverDoesNotExistException;
-import digital.slovensko.autogram.core.errors.TokenNotRecognizedException;
-import digital.slovensko.autogram.core.errors.TokenRemovedException;
-import digital.slovensko.autogram.core.errors.UnableToCreateDirectoryException;
+import digital.slovensko.autogram.core.errors.*;
import digital.slovensko.autogram.core.visualization.Visualization;
import digital.slovensko.autogram.drivers.TokenDriver;
import digital.slovensko.autogram.ui.BatchUiResult;
@@ -275,6 +255,8 @@ public void showError(AutogramException e) {
errMessage = "Slot ID is not a number";
} else if (e instanceof PDFSignatureLevelIsNotValidException) {
errMessage = "PDF signature level is not valid";
+ } else if (e instanceof KeyPinDifferentFromTokenPinException) {
+ errMessage = "PIN for signing key is different from card PIN. Not supported.";
} else {
errMessage = "Unknown error occurred";
e.printStackTrace();
diff --git a/src/main/java/digital/slovensko/autogram/ui/gui/GUI.java b/src/main/java/digital/slovensko/autogram/ui/gui/GUI.java
index 27742d0a8..54987478a 100644
--- a/src/main/java/digital/slovensko/autogram/ui/gui/GUI.java
+++ b/src/main/java/digital/slovensko/autogram/ui/gui/GUI.java
@@ -8,15 +8,10 @@
import java.util.function.Consumer;
import digital.slovensko.autogram.core.*;
+import digital.slovensko.autogram.core.errors.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import digital.slovensko.autogram.core.errors.AutogramException;
-import digital.slovensko.autogram.core.errors.NoDriversDetectedException;
-import digital.slovensko.autogram.core.errors.NoKeysDetectedException;
-import digital.slovensko.autogram.core.errors.NoValidKeysDetectedException;
-import digital.slovensko.autogram.core.errors.SigningCanceledByUserException;
-import digital.slovensko.autogram.core.errors.TokenRemovedException;
import digital.slovensko.autogram.core.visualization.Visualization;
import digital.slovensko.autogram.drivers.TokenDriver;
import digital.slovensko.autogram.ui.BatchUiResult;
@@ -80,13 +75,15 @@ public void cancelBatch(Batch batch) {
}
@Override
- public void signBatch(SigningJob job, SigningKey key) {
+ public void signBatch(SigningJob job, SigningKey key) throws KeyPinDifferentFromTokenPinException {
assertOnWorkThread();
try {
job.signWithKeyAndRespond(key);
Logging.log("GUI: Signing batch job: " + job.hashCode() + " file " + job.getDocument().getName());
} catch (AutogramException e) {
job.onDocumentSignFailed(e);
+ if (!e.batchCanContinue())
+ throw e;
} catch (DSSException e) {
job.onDocumentSignFailed(AutogramException.createFromDSSException(e));
} catch (Exception e) {
diff --git a/src/main/scripts/package.sh b/src/main/scripts/package.sh
index f469da204..ab6c8c7d6 100644
--- a/src/main/scripts/package.sh
+++ b/src/main/scripts/package.sh
@@ -27,7 +27,7 @@ while read -r key value; do
done <"$resourcesDir/build.properties"
unset IFS
-jvmOptions="-Dfile.encoding=UTF-8 -Dprism.maxvram=2G --add-exports javafx.graphics/com.sun.javafx.tk=ALL-UNNAMED"
+jvmOptions="-Dfile.encoding=UTF-8 -Dprism.maxvram=2G --add-exports javafx.graphics/com.sun.javafx.tk=ALL-UNNAMED --add-exports jdk.crypto.cryptoki/sun.security.pkcs11.wrapper=ALL-UNNAMED --add-opens java.base/java.security=ALL-UNNAMED --add-opens jdk.crypto.cryptoki/sun.security.pkcs11=ALL-UNNAMED"
arguments=(
"--input" "$appDirectory"
"--runtime-image" "$jdkDirectory"