Search code examples
javamavencode-signingjava-web-startmaven-webstart-plugin

Maven JNLP creation with EV Code Signing


I'm using Maven and the webstart-maven-plugin to generate a JNLP file and sign the jar files of my project. We just had to renew our Code Signing certificate and since February 2017, hardware tokens are provided instead of software ones.

According to the GlobalSign support page, the correct way to sign jars with the hardware token is as following (see article):

jarsigner -keystore NONE -storetype PKCS11 -tsa http://timestamp.globalsign.com/scripts/timestamp.dll -providerClass sun.security.pkcs11.SunPKCS11 -providerArg eToken.cfg test.jar "le-d0e453de-66db-414a-8fa8-0a07cfad66b5"

I followed all the steps described in that article and now I'm trying to adjust my pom.xml to apply the EV Code Signing certificate.

Originally I used a keystore (snippet, full pom below):

<!-- SIGNING -->
<sign>
    <keystore>${project.basedir}/src/main/jnlp/my.keystore</keystore>
    <keypass>...</keypass>
    <storepass>...</storepass>
    <alias>...</alias>
    <verify>true</verify>
</sign>

Now I'm trying to update it to get EV Code Signing to work (snippet, full pom below):

<!-- SIGNING -->
<sign>
    <keystore>NONE</keystore>
    <storetype>PKCS11</storetype>
    <storepass>...</storepass>
    <tsa>http://timestamp.globalsign.com/scripts/timestamp.dll</tsa>
    <providerClass>sun.security.pkcs11.SunPKCS11</providerClass>
    <providerArg>${project.basedir}/src/main/resources/token/eToken.config</providerArg>
    <alias>le-d0e453de-66db-414a-8fa8-0a07cfad66b5</alias> <!-- I took the alias from the article as an example -->
    <verify>true</verify>
</sign>

However, it seems that tsa, providerClass and providerArg are not supported unless I missed something. I did not find alot of information about the webstart-maven-plugin or it's not up to date, which is a shame :(

Is there another/better way to sign jars while creating a JNLP? Any help would be much appreciated!

pom.xml code signing (with keystore)

    <profile>
        <id>jnlp</id>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.codehaus.mojo</groupId>
                    <artifactId>webstart-maven-plugin</artifactId>
                    <version>1.0-beta-6</version>
                    <dependencies>
                        <dependency>
                            <groupId>org.codehaus.mojo</groupId>
                            <artifactId>webstart-pack200-impl</artifactId>
                            <version>1.0-beta-6</version>
                        </dependency>
                        <dependency>
                            <groupId>org.codehaus.mojo</groupId>
                            <artifactId>keytool-api-1.7</artifactId>
                            <version>1.5</version>
                        </dependency>
                    </dependencies>
                    <executions>
                        <execution>
                            <phase>package</phase>
                            <goals>
                                <goal>jnlp</goal>
                            </goals>
                        </execution>
                    </executions>
                    <configuration>
                        <!-- The path where the libraries are stored within the jnlp structure. not required. by default the libraries are within the working directory -->
                        <libPath>lib</libPath>
                        <!-- JNLP generation -->
                        <jnlp>
                            <mainClass>myApp.ui.MainApp</mainClass>
                        </jnlp>

                        <!-- SIGNING -->
                        <sign>
                            <keystore>${project.basedir}/src/main/jnlp/my.keystore</keystore>
                            <keypass>...</keypass>
                            <storepass>...</storepass>
                            <alias>...</alias>
                            <verify>true</verify>
                        </sign>
                        <verbose>true</verbose>
                        <updateManifestEntries>
                            <Application-Name>MyApp</Application-Name>
                            <Permissions>all-permissions</Permissions>
                            <Codebase>...</Codebase>
                            <Application-Library-Allowable-Codebase>...</Application-Library-Allowable-Codebase>
                            <Caller-Allowable-Codebase>...</Caller-Allowable-Codebase>
                        </updateManifestEntries>

                        <!-- BUILDING PROCESS -->
                        <pack200>
                            <enabled>false</enabled>
                        </pack200>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-assembly-plugin</artifactId>
                    <version>2.6</version>
                    <configuration>
                        <descriptorRefs>
                            <descriptorRef>jar-with-dependencies</descriptorRef>
                        </descriptorRefs>
                    </configuration>
                    <executions>
                        <execution>
                            <id>assemble-all</id>
                            <phase>package</phase>
                            <goals>
                                <goal>single</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </build>
    </profile>

pom.xml EV Code Signing (with SafeNet token)

    <profile>
        <id>jnlp</id>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.codehaus.mojo</groupId>
                    <artifactId>webstart-maven-plugin</artifactId>
                    <version>1.0-beta-7</version>
                    <dependencies>
                        <dependency>
                            <groupId>org.codehaus.mojo</groupId>
                            <artifactId>webstart-pack200-impl</artifactId>
                            <version>1.0-beta-6</version>
                        </dependency>
                        <dependency>
                            <groupId>org.codehaus.mojo</groupId>
                            <artifactId>keytool-api-1.7</artifactId>
                            <version>1.5</version>
                        </dependency>
                    </dependencies>
                    <executions>
                        <execution>
                            <phase>package</phase>
                            <goals>
                                <goal>jnlp</goal>
                            </goals>
                        </execution>
                    </executions>
                    <configuration>
                        <!-- The path where the libraries are stored within the jnlp structure. not required. by default the libraries are within the working directory -->
                        <libPath>lib</libPath>
                        <!-- JNLP generation -->
                        <jnlp>
                            <mainClass>myApp.ui.MainApp</mainClass>
                        </jnlp>

                        <!-- SIGNING -->
                        <sign>
                            <keystore>NONE</keystore>
                            <storetype>PKCS11</storetype>
                            <storepass>...</storepass>
                            <tsa>http://timestamp.globalsign.com/scripts/timestamp.dll</tsa>
                            <providerClass>sun.security.pkcs11.SunPKCS11</providerClass>
                            <providerArg>${project.basedir}/src/main/resources/token/eToken.config</providerArg>
                            <alias>le-d0e453de-66db-414a-8fa8-0a07cfad66b5</alias> <!-- i took the alias from the article as an example -->
                            <verify>true</verify>
                        </sign>
                        <verbose>true</verbose>
                        <updateManifestEntries>
                            <Application-Name>MyApp</Application-Name>
                            <Permissions>all-permissions</Permissions>
                            <Codebase>...</Codebase>
                            <Application-Library-Allowable-Codebase>...</Application-Library-Allowable-Codebase>
                            <Caller-Allowable-Codebase>...</Caller-Allowable-Codebase>
                        </updateManifestEntries>

                        <!-- BUILDING PROCESS -->
                        <pack200>
                            <enabled>false</enabled>
                        </pack200>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-assembly-plugin</artifactId>
                    <version>2.6</version>
                    <configuration>
                        <descriptorRefs>
                            <descriptorRef>jar-with-dependencies</descriptorRef>
                        </descriptorRefs>
                    </configuration>
                    <executions>
                        <execution>
                            <id>assemble-all</id>
                            <phase>package</phase>
                            <goals>
                                <goal>single</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
        </build>
    </profile>

Solution

  • Disclaimer: I'm the maintainer of the javafx-maven-plugin.

    This got reported and now being available, for more information see this link: https://github.com/javafx-maven-plugin/javafx-maven-plugin/issues/291

    As already mentioned on the javafx-maven-plugin, here is the solution to get this working:

    <plugin>
        <groupId>com.zenjava</groupId>
        <artifactId>javafx-maven-plugin</artifactId>
        <version>8.8.4-SNAPSHOT</version>
        <!-- this configuration is share among all executions -->
        <configuration>
            <mainClass>fqdn.to.your.MainClass</mainClass>
            <description>test signing</description>
            <title>launch</title>
            <verbose>true</verbose>
            <j2seVersion>1.8+</j2seVersion>
            <appName>simpleApplicationName</appName>
    
            <!-- this only sets the field inside jar-file -->
            <allPermissions>true</allPermissions>
        </configuration>
        <executions>
            <execution>
                <!-- required before build-native, creates target/jfx/app -->
                <id>create-jfxjar</id>
                <phase>package</phase>
                <goals>
                    <goal>build-jar</goal>
                </goals>
            </execution>
            <execution>
                <!-- creates target/jfx/web -->
                <id>create-jnlp-bundle</id>
                <phase>package</phase>
                <goals>
                    <goal>build-native</goal>
                </goals>
                <!-- this configuration is only specific to this execution -->
                <configuration>
                    <!-- as we only want to create the JNLP-package, use fixed bundler-ID -->
                    <bundler>jnlp<bundler>
    
                    <bundleArguments>
                        <!-- this makes the JNLP-file having permissions being set -->
                        <!-- AND it is the trigger for signing jar-files using jarsigner -->
                        <jnlp.allPermisions>true</jnlp.allPermisions>
    
                        <!-- the JNLP-bundler is a bit picky about its parametes, it does not use <appName> -->
                        <jnlp.outfile>simpleApplicationName</jnlp.outfile>
                    </bundleArguments>
    
                    <!-- this setting is required for the new "jarsigner"-feature -->
                    <noBlobSigning>true</noBlobSigning>
    
                    <!-- these are required, please change them for your own requirements -->
                    <keyStoreAlias>myalias</keyStoreAlias>
                    <keyStorePassword>mypass</keyStorePassword>
    
                    <!-- as this keystore is no file, please disable file-checks -->
                    <skipKeyStoreChecking>true</skipKeyStoreChecking>
                    <!-- this is new too and required, as PKCS11 does not want some keypass -->
                    <skipKeypassWhileSigning>true</skipKeypassWhileSigning>
    
                    <!-- this is used for additional parameters for the jarsigner command -->
                    <additionalJarsignerParameters>
                        <additionalJarsignerParameter>-keystore</additionalJarsignerParameter>
                        <additionalJarsignerParameter>NONE</additionalJarsignerParameter>
                        <additionalJarsignerParameter>-storetype</additionalJarsignerParameter>
                        <additionalJarsignerParameter>PKCS11</additionalJarsignerParameter>
                        <additionalJarsignerParameter>-tsa</additionalJarsignerParameter>
                        <additionalJarsignerParameter>http://timestamp.globalsign.com/scripts/timestamp.dll</additionalJarsignerParameter>
                        <additionalJarsignerParameter>-providerClass</additionalJarsignerParameter>
                        <additionalJarsignerParameter>sun.security.pkcs11.SunPKCS11</additionalJarsignerParameter>
                        <additionalJarsignerParameter>-providerArg</additionalJarsignerParameter>
                        <additionalJarsignerParameter>${project.basedir}/src/main/resources/token/eToken.config</additionalJarsignerParameter>
                        <!-- I DO KNOW that this is verbose ... -->
                    </additionalJarsignerParameters>
    
                    <!-- the jnlp-bundler gets a bit messy, lots of files, so we want to mimic "jfx:web"-folder-structure -->
                    <nativeOutputDir>${project.build.directory}/jfx/web</nativeOutputDir>
                </configuration>
            </execution>
        </executions>
    </plugin>
    

    This version is not yet released but available as SNAPSHOT from the sonatype-repository.