# Task :signModule FAILED

**URL:** <https://forum.inductiveautomation.com/t/task-signmodule-failed/94953>\
**Category:** Module Development\
**Created:** [August 21, 2024, 3:46pm UTC](https://forum.inductiveautomation.com/t/task-signmodule-failed/94953 "2024-08-21T15:46:28Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![ahoover](https://avatars.discourse-cdn.com/v4/letter/a/35a633/32.png) [@ahoover](https://forum.inductiveautomation.com/u/ahoover)\
**Post date:** [August 21, 2024, 3:46pm UTC](https://forum.inductiveautomation.com/t/task-signmodule-failed/94953/1 "2024-08-21T15:46:28Z")

</div>

After reading [How can we perform code signing using an HSM with module-signer? - #21 by Brian\_Ray](https://forum.inductiveautomation.com/t/how-can-we-perform-code-signing-using-an-hsm-with-module-signer/85640/21), I changed our module build process to use Gradle to take advantage of signing with our hardware based code signing certificate. I've gone through more attempts than I can remember to get this to work. I'm stuck at this stack trace produced by `gradlew build --stacktrace` that I can't seem to get past.

```python
org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':signModule'.
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.lambda$executeIfValid$1(ExecuteActionsTaskExecuter.java:142)
        at org.gradle.internal.Try$Failure.ifSuccessfulOrElse(Try.java:282)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeIfValid(ExecuteActionsTaskExecuter.java:140)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:128)
        at org.gradle.api.internal.tasks.execution.CleanupStaleOutputsExecuter.execute(CleanupStaleOutputsExecuter.java:77)
        at org.gradle.api.internal.tasks.execution.FinalizePropertiesTaskExecuter.execute(FinalizePropertiesTaskExecuter.java:46)
        at org.gradle.api.internal.tasks.execution.ResolveTaskExecutionModeExecuter.execute(ResolveTaskExecutionModeExecuter.java:51)
        at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:57)
        at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:57)
        at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:36)
        at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.executeTask(EventFiringTaskExecuter.java:77)
        at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:55)
        at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:52)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:199)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:73)
        at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter.execute(EventFiringTaskExecuter.java:52)
        at org.gradle.execution.plan.LocalTaskNodeExecutor.execute(LocalTaskNodeExecutor.java:69)
        at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:322)
        at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:309)
        at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:302)
        at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:288)
        at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.execute(DefaultPlanExecutor.java:462)
        at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.run(DefaultPlanExecutor.java:379)
        at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
        at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:49)
Caused by: java.security.ProviderException: Initialization failed
        at io.ia.sdk.gradle.modl.task.SignModule.getKeyStore(SignModule.kt:276)
        at io.ia.sdk.gradle.modl.task.SignModule.signModule(SignModule.kt:354)
        at io.ia.sdk.gradle.modl.task.SignModule.execute(SignModule.kt:327)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:125)
        at org.gradle.api.internal.project.taskfactory.StandardTaskAction.doExecute(StandardTaskAction.java:58)
        at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:51)
        at org.gradle.api.internal.project.taskfactory.StandardTaskAction.execute(StandardTaskAction.java:29)
        at org.gradle.api.internal.tasks.execution.TaskExecution$3.run(TaskExecution.java:236)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:29)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$1.execute(DefaultBuildOperationRunner.java:26)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.run(DefaultBuildOperationRunner.java:47)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:68)
        at org.gradle.api.internal.tasks.execution.TaskExecution.executeAction(TaskExecution.java:221)
        at org.gradle.api.internal.tasks.execution.TaskExecution.executeActions(TaskExecution.java:204)
        at org.gradle.api.internal.tasks.execution.TaskExecution.executeWithPreviousOutputFiles(TaskExecution.java:187)
        at org.gradle.api.internal.tasks.execution.TaskExecution.execute(TaskExecution.java:165)
        at org.gradle.internal.execution.steps.ExecuteStep.executeInternal(ExecuteStep.java:89)
        at org.gradle.internal.execution.steps.ExecuteStep.access$000(ExecuteStep.java:40)
        at org.gradle.internal.execution.steps.ExecuteStep$1.call(ExecuteStep.java:53)
        at org.gradle.internal.execution.steps.ExecuteStep$1.call(ExecuteStep.java:50)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:199)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:73)
        at org.gradle.internal.execution.steps.ExecuteStep.execute(ExecuteStep.java:50)
        at org.gradle.internal.execution.steps.ExecuteStep.execute(ExecuteStep.java:40)
        at org.gradle.internal.execution.steps.RemovePreviousOutputsStep.execute(RemovePreviousOutputsStep.java:68)
        at org.gradle.internal.execution.steps.RemovePreviousOutputsStep.execute(RemovePreviousOutputsStep.java:38)
        at org.gradle.internal.execution.steps.CancelExecutionStep.execute(CancelExecutionStep.java:41)
        at org.gradle.internal.execution.steps.TimeoutStep.executeWithoutTimeout(TimeoutStep.java:74)
        at org.gradle.internal.execution.steps.TimeoutStep.execute(TimeoutStep.java:55)
        at org.gradle.internal.execution.steps.CreateOutputsStep.execute(CreateOutputsStep.java:51)
        at org.gradle.internal.execution.steps.CreateOutputsStep.execute(CreateOutputsStep.java:29)
        at org.gradle.internal.execution.steps.CaptureStateAfterExecutionStep.executeDelegateBroadcastingChanges(CaptureStateAfterExecutionStep.java:124)
        at org.gradle.internal.execution.steps.CaptureStateAfterExecutionStep.execute(CaptureStateAfterExecutionStep.java:80)
        at org.gradle.internal.execution.steps.CaptureStateAfterExecutionStep.execute(CaptureStateAfterExecutionStep.java:58)
        at org.gradle.internal.execution.steps.ResolveInputChangesStep.execute(ResolveInputChangesStep.java:48)
        at org.gradle.internal.execution.steps.ResolveInputChangesStep.execute(ResolveInputChangesStep.java:36)
        at org.gradle.internal.execution.steps.BuildCacheStep.executeWithoutCache(BuildCacheStep.java:181)
        at org.gradle.internal.execution.steps.BuildCacheStep.lambda$execute$1(BuildCacheStep.java:71)
        at org.gradle.internal.Either$Right.fold(Either.java:175)
        at org.gradle.internal.execution.caching.CachingState.fold(CachingState.java:59)
        at org.gradle.internal.execution.steps.BuildCacheStep.execute(BuildCacheStep.java:69)
        at org.gradle.internal.execution.steps.BuildCacheStep.execute(BuildCacheStep.java:47)
        at org.gradle.internal.execution.steps.StoreExecutionStateStep.execute(StoreExecutionStateStep.java:36)
        at org.gradle.internal.execution.steps.StoreExecutionStateStep.execute(StoreExecutionStateStep.java:25)
        at org.gradle.internal.execution.steps.RecordOutputsStep.execute(RecordOutputsStep.java:36)
        at org.gradle.internal.execution.steps.RecordOutputsStep.execute(RecordOutputsStep.java:22)
        at org.gradle.internal.execution.steps.SkipUpToDateStep.executeBecause(SkipUpToDateStep.java:110)
        at org.gradle.internal.execution.steps.SkipUpToDateStep.lambda$execute$2(SkipUpToDateStep.java:56)
        at org.gradle.internal.execution.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:56)
        at org.gradle.internal.execution.steps.SkipUpToDateStep.execute(SkipUpToDateStep.java:38)
        at org.gradle.internal.execution.steps.ResolveChangesStep.execute(ResolveChangesStep.java:73)
        at org.gradle.internal.execution.steps.ResolveChangesStep.execute(ResolveChangesStep.java:44)
        at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:37)
        at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsFinishedStep.execute(MarkSnapshottingInputsFinishedStep.java:27)
        at org.gradle.internal.execution.steps.ResolveCachingStateStep.execute(ResolveCachingStateStep.java:89)
        at org.gradle.internal.execution.steps.ResolveCachingStateStep.execute(ResolveCachingStateStep.java:50)
        at org.gradle.internal.execution.steps.ValidateStep.execute(ValidateStep.java:102)
        at org.gradle.internal.execution.steps.ValidateStep.execute(ValidateStep.java:57)
        at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.execute(CaptureStateBeforeExecutionStep.java:76)
        at org.gradle.internal.execution.steps.CaptureStateBeforeExecutionStep.execute(CaptureStateBeforeExecutionStep.java:50)
        at org.gradle.internal.execution.steps.SkipEmptyWorkStep.executeWithNoEmptySources(SkipEmptyWorkStep.java:254)
        at org.gradle.internal.execution.steps.SkipEmptyWorkStep.execute(SkipEmptyWorkStep.java:91)
        at org.gradle.internal.execution.steps.SkipEmptyWorkStep.execute(SkipEmptyWorkStep.java:56)
        at org.gradle.internal.execution.steps.RemoveUntrackedExecutionStateStep.execute(RemoveUntrackedExecutionStateStep.java:32)
        at org.gradle.internal.execution.steps.RemoveUntrackedExecutionStateStep.execute(RemoveUntrackedExecutionStateStep.java:21)
        at org.gradle.internal.execution.steps.legacy.MarkSnapshottingInputsStartedStep.execute(MarkSnapshottingInputsStartedStep.java:38)
        at org.gradle.internal.execution.steps.LoadPreviousExecutionStateStep.execute(LoadPreviousExecutionStateStep.java:43)
        at org.gradle.internal.execution.steps.LoadPreviousExecutionStateStep.execute(LoadPreviousExecutionStateStep.java:31)
        at org.gradle.internal.execution.steps.AssignWorkspaceStep.lambda$execute$0(AssignWorkspaceStep.java:40)
        at org.gradle.api.internal.tasks.execution.TaskExecution$4.withWorkspace(TaskExecution.java:281)
        at org.gradle.internal.execution.steps.AssignWorkspaceStep.execute(AssignWorkspaceStep.java:40)
        at org.gradle.internal.execution.steps.AssignWorkspaceStep.execute(AssignWorkspaceStep.java:30)
        at org.gradle.internal.execution.steps.IdentityCacheStep.execute(IdentityCacheStep.java:37)
        at org.gradle.internal.execution.steps.IdentityCacheStep.execute(IdentityCacheStep.java:27)
        at org.gradle.internal.execution.steps.IdentifyStep.execute(IdentifyStep.java:44)
        at org.gradle.internal.execution.steps.IdentifyStep.execute(IdentifyStep.java:33)
        at org.gradle.internal.execution.impl.DefaultExecutionEngine$1.execute(DefaultExecutionEngine.java:76)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeIfValid(ExecuteActionsTaskExecuter.java:139)
        at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:128)
        at org.gradle.api.internal.tasks.execution.CleanupStaleOutputsExecuter.execute(CleanupStaleOutputsExecuter.java:77)
        at org.gradle.api.internal.tasks.execution.FinalizePropertiesTaskExecuter.execute(FinalizePropertiesTaskExecuter.java:46)
        at org.gradle.api.internal.tasks.execution.ResolveTaskExecutionModeExecuter.execute(ResolveTaskExecutionModeExecuter.java:51)
        at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:57)
        at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:57)
        at org.gradle.api.internal.tasks.execution.CatchExceptionTaskExecuter.execute(CatchExceptionTaskExecuter.java:36)
        at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.executeTask(EventFiringTaskExecuter.java:77)
        at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:55)
        at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter$1.call(EventFiringTaskExecuter.java:52)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:204)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$CallableBuildOperationWorker.execute(DefaultBuildOperationRunner.java:199)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:66)
        at org.gradle.internal.operations.DefaultBuildOperationRunner$2.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:157)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.execute(DefaultBuildOperationRunner.java:59)
        at org.gradle.internal.operations.DefaultBuildOperationRunner.call(DefaultBuildOperationRunner.java:53)
        at org.gradle.internal.operations.DefaultBuildOperationExecutor.call(DefaultBuildOperationExecutor.java:73)
        at org.gradle.api.internal.tasks.execution.EventFiringTaskExecuter.execute(EventFiringTaskExecuter.java:52)
        at org.gradle.execution.plan.LocalTaskNodeExecutor.execute(LocalTaskNodeExecutor.java:69)
        at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:322)
        at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$InvokeNodeExecutorsAction.execute(DefaultTaskExecutionGraph.java:309)
        at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:302)
        at org.gradle.execution.taskgraph.DefaultTaskExecutionGraph$BuildOperationAwareExecutionAction.execute(DefaultTaskExecutionGraph.java:288)
        at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.execute(DefaultPlanExecutor.java:462)
        at org.gradle.execution.plan.DefaultPlanExecutor$ExecutorWorker.run(DefaultPlanExecutor.java:379)
        at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
        at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:49)
Caused by: java.security.ProviderException: slotListIndex is 0 but token only has 0 slots
        ... 119 more

```

Some relevant settings from build.gradle.kts

```python
    plugins {
        id("io.ia.sdk.modl") version("0.3.0")
    }
...
    skipModlSigning.set(false)

```

I added the following to a gradle.properties file that's located in the root folder of the module where the build.gradle.kts and gradlew files are located.

```python
ignition.signing.pkcs11CfgFile=eToken.cfg
ignition.signing.certAlias=p11#6287f477251b9ed7
ignition.signing.certFile=CanaryLabs.cer
ignition.signing.inputFile="C:\IgnitionModules\repos\git\IgnitionModules\canary-historian\build\Canary-Historian.unsigned.modl"
ignition.signing.outputFile="C:\IgnitionModules\repos\git\IgnitionModules\canary-historian\build\Canary-Historian.signed.modl"
ignition.signing.keystorePassword=<token password>

```

The debug output from the gradle build shows that it is using PKCS11 and it is pulling all of the values from the gradle.properties, but it seems to fail to access a keystore. We have a DigiCert 5110 CC eToken plugged into our build server vm host in the rack in the server room. We're using it to code sign our C# builds. To the best of my knowledge it has no slots configured, so the `java.security.ProviderException: slotListIndex is 0 but token only has 0 slots` line from the stack trace might have a bearing, but it might not. I'm not sure if I put the token password in the right setting or if I'm missing something else. Has anyone been able to sign a module with this process?

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [August 21, 2024, 4:01pm UTC](https://forum.inductiveautomation.com/t/task-signmodule-failed/94953/2 "2024-08-21T16:01:56Z")

</div>

It's on my to-do list, but my (future) experience won't help you, I think. I do not develop in Windows--all of my operations use Linux pkcs11 libraries.

(All of my current modules use a customized `ant` build that calls the signer functionality directly. Works with both Yubikeys and Nitrokeys with the generic libraries.)

Consider running the signer from the command line to ensure your `eToken.cfg` isn't the problem.

---

<div class="post-metadata">

**Author:** ![Kevin.Herron](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/kevin.herron/32/7259_2.png) [@Kevin.Herron](https://forum.inductiveautomation.com/u/Kevin.Herron)\
**Post date:** [August 21, 2024, 4:29pm UTC](https://forum.inductiveautomation.com/t/task-signmodule-failed/94953/4 "2024-08-21T16:29:29Z")

</div>

This thread is about using a hardware signing module to sign modules, it's not quite as straightforward as what's going on there.

---

<div class="post-metadata">

**Author:** ![Brian\_Ray](https://avatars.discourse-cdn.com/v4/letter/b/e0b2c6/32.png) [@Brian\_Ray](https://forum.inductiveautomation.com/u/Brian_Ray)\
**Post date:** [August 21, 2024, 4:31pm UTC](https://forum.inductiveautomation.com/t/task-signmodule-failed/94953/5 "2024-08-21T16:31:25Z")

</div>

The ultimate (?) `ProviderException` concerning the slots does not make sense to me. But HSMs proved inconsistent in my experience. I developed the PKCS#11 support on Windows so signing can work on Windows, but e.g., I could not get a Nitrokey 3A NFC to work but _could_ get a YubiKey 5 NFC to work. (Inexpensive, but non-FIPS compliant.)

An integrator was looking into the similar DC eToken 5110 FIPS but have not heard the outcome, whether they purchased it and were successful.

@pturmel recommends running the signer from the command line; he might be referring to the technique [I used here](https://support.nitrokey.com/t/nitrokey-3a-nfc-and-java-sun-pkcs-11/5916) if by "signer" he means `keytool`.

`keytool` was my smoke test and troubleshooter for these devices because it's using the same `SunPKCS11` provider as the Gradle module signer, assuming you're building with the same JDK that you're running `keytool` from.

That is, signing with other tools like `gpg` is a valid test of the driver(s) and the token, but not the Java that sits on top of it--and under the module signer logic--in the current use case.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [August 21, 2024, 4:51pm UTC](https://forum.inductiveautomation.com/t/task-signmodule-failed/94953/6 "2024-08-21T16:51:33Z")

</div>

> [@Brian\_Ray](#):
>
> if by "signer" he means `keytool`.

No, my ant builds have this nested in a task:

```python
<java fork="true" jar="${basedir}/../module-signer/target/module-signer-1.0.0-SNAPSHOT-jar-with-dependencies.jar">
	<arg value="-pkcs11-cfg=${basedir}/pkcs11.cfg"/>
	<arg value="-alias=Certificate for PIV Authentication"/>
	<arg value="-keystore-pwd=${keystorepw}"/>
	<arg value="-alias-pwd=${keystorepw}"/>
	<arg value="-chain=${basedir}/autopros-code-signer.p7b"/>
	<arg value="-module-in=${basedir}/Build/modules/${module.name}-${asbuiltversion}-unsigned.modl"/>
	<arg value="-module-out=${basedir}/Build/modules/${module.name}-${asbuiltversion}-v81.modl"/>
</java>

```

Which boils down to a command line like:

```python
java -jar "${basedir}/../module-signer/target/module-signer-1.0.0-SNAPSHOT-jar-with-dependencies.jar" \
	-pkcs11-cfg="${basedir}/pkcs11.cfg" \
	-alias="Certificate for PIV Authentication" \
	-keystore-pwd="${keystorepw}" \
	-alias-pwd="${keystorepw}" \
	-chain="${basedir}/autopros-code-signer.p7b" \
	-module-in="${basedir}/Build/modules/${module.name}-${asbuiltversion}-unsigned.modl" \
	-module-out="${basedir}/Build/modules/${module.name}-${asbuiltversion}-v81.modl"

```

---

<div class="post-metadata">

**Author:** ![ahoover](https://avatars.discourse-cdn.com/v4/letter/a/35a633/32.png) [@ahoover](https://forum.inductiveautomation.com/u/ahoover)\
**Post date:** [August 21, 2024, 8:11pm UTC](https://forum.inductiveautomation.com/t/task-signmodule-failed/94953/7 "2024-08-21T20:11:22Z")

</div>

Thank you for the suggestions. I think you've put me on the right path. Signing a jar with the jarsigner, and following DigiCert's guide to access the cert using the keytool both yielded the same result: `java.security.ProviderException: Initialization failed`

The eToken.cfg is currently pointing to the opensc-pks.dll which managed to solve one of my iterations of issues with the process, but is apparently not the right dll. I'll try some other options and post the results.

Thanks!

---

<div class="post-metadata">

**Author:** ![Brian\_Ray](https://avatars.discourse-cdn.com/v4/letter/b/e0b2c6/32.png) [@Brian\_Ray](https://forum.inductiveautomation.com/u/Brian_Ray)\
**Post date:** [August 21, 2024, 10:25pm UTC](https://forum.inductiveautomation.com/t/task-signmodule-failed/94953/8 "2024-08-21T22:25:14Z")

</div>

That sounds similar to my adventures with the Nitrokey and the YubiKey. For example, I had to use the vendor DLL for the latter in testing as in this [test fixture up on the `ignition-module-tools` repository](https://github.com/inductiveautomation/ignition-module-tools/blob/a3f4a6cad2ac7ec4a0a33463e1ed52fe3d1d605a/gradle-module-plugin/src/functionalTest/resources/certs/pkcs11-yk5-win.cfg#L6).

There was no similar vendor DLL at the time for my Nitrokey (though there was for a different Nitrokey HSM) so I too tried to use the OpenSC "generic" driver and did not get very far.

Good luck.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [August 21, 2024, 10:28pm UTC](https://forum.inductiveautomation.com/t/task-signmodule-failed/94953/9 "2024-08-21T22:28:17Z")

</div>

In Linux, this pkcs11.cfg content works with both Yubikeys and Nitrokeys:

```python
name = OpenSC
library = /usr/lib/x86_64-linux-gnu/opensc-pkcs11.so
description = OpenSC PKCS11 Provider

```

🤷‍♂️

---

<div class="post-metadata">

**Author:** ![Brian\_Ray](https://avatars.discourse-cdn.com/v4/letter/b/e0b2c6/32.png) [@Brian\_Ray](https://forum.inductiveautomation.com/u/Brian_Ray)\
**Post date:** [August 21, 2024, 10:28pm UTC](https://forum.inductiveautomation.com/t/task-signmodule-failed/94953/10 "2024-08-21T22:28:21Z")

</div>

Also, at the time my Nitrokey was a very new model; clearly from Phil's experience Nitrokeys can do SunPKCS11 signing. I think the firmware needed to catch up or something similar for the 3A.

Side note: Regard the [velocity on the NK 3 firmware repo](https://github.com/Nitrokey/nitrokey-3-firmware/releases).

---

<div class="post-metadata">

**Author:** ![ahoover](https://avatars.discourse-cdn.com/v4/letter/a/35a633/32.png) [@ahoover](https://forum.inductiveautomation.com/u/ahoover)\
**Post date:** [September 4, 2024, 6:43pm UTC](https://forum.inductiveautomation.com/t/task-signmodule-failed/94953/11 "2024-09-04T18:43:01Z")

</div>

Success! In working with DigiCert's support, I learned that token access is blocked via RDP so you have to be signed directly onto the machine to work with it. Once that was resolved, it was a question of standing in the server room until finding the right combination of settings to get the module signed. I was using a name that's used by our C# builds for the certificate alias, but that was not the right value. The correct value is what the keytool returned for the certificate with this call `Keytool -list -keystore NONE -storetype PKCS11 -providerclass sun.security.pkcs11.SunPKCS11 -providerArg eToken.cfg`.

Thanks,  
Andy
