Skip to content

NIFI-15675 - Add NAR signing support using JDK JarSigner#48

Open
pvillard31 wants to merge 2 commits intoapache:mainfrom
pvillard31:NIFI-15675
Open

NIFI-15675 - Add NAR signing support using JDK JarSigner#48
pvillard31 wants to merge 2 commits intoapache:mainfrom
pvillard31:NIFI-15675

Conversation

@pvillard31
Copy link
Contributor

https://issues.apache.org/jira/browse/NIFI-15675

Add NAR signing support using JDK JarSigner

When NiFi dynamically downloads or auto-loads NARs from external sources, there is currently no mechanism to verify that a NAR has not been tampered with or that it originates from a trusted publisher. This is the build-side prerequisite for enabling signature verification in the NiFi runtime.

Since a NAR is structurally a JAR, the JDK's built-in JAR signing mechanism is the natural fit. This issue covers adding optional signing parameters to the existing goal in the plugin. Signing is disabled by default for full backward compatibility. A follow-up issue will cover runtime verification in NiFi itself.

  • Adds optional NAR signing to the existing nar goal using the JDK's jdk.security.jarsigner.JarSigner API
  • Signing is disabled by default (nar.sign=false) — fully backward compatible, no behavioral change unless explicitly opted in
  • After createArchive() produces the NAR, the new signNar() step signs it in place using the configured keystore, then the signed NAR is registered as the project artifact

Configuration

Seven new parameters on the nar goal, all optional:

Parameter Property Default Description
sign nar.sign false Enable signing
signKeystore nar.sign.keystore Path to PKCS12/JKS keystore
signStorepass nar.sign.storepass Keystore password
signAlias nar.sign.alias Key alias
signKeypass nar.sign.keypass Key password (defaults to storepass)
signStoretype nar.sign.storetype PKCS12 Keystore type
signTsa nar.sign.tsa TSA URL for timestamping

Minimal usage:

<configuration>
    <sign>true</sign>
    <signKeystore>/path/to/keystore.p12</signKeystore>
    <signStorepass>${env.NAR_SIGN_PASSWORD}</signStorepass>
    <signAlias>nar-signer</signAlias>
</configuration>

Or entirely via command line with no POM changes:

mvn package -Dnar.sign=true -Dnar.sign.keystore=... -Dnar.sign.storepass=... -Dnar.sign.alias=...

Signed NARs can be verified with standard JDK tooling: jarsigner -verify -verbose -certs target/my.nar

Approach

A NAR is structurally a JAR. Rather than inventing a custom signature format, this uses the JDK's JarSigner API (available since Java 9, stable in Java 21) which signs each entry inside the archive with SHA-256 digests and produces standard PKCS#7 signature blocks. This means:

  • Zero custom signature format — uses the decades-old JAR signing standard
  • Interoperable — verifiable with jarsigner -verify by anyone
  • No new dependencies — jdk.security.jarsigner.JarSigner is part of the JDK itself
  • No changes to the NAR file format — the signature lives in META-INF/ like any signed JAR

Verification building nifi-aws-nar

NAR build

...
[INFO] Building jar: /.../nifi/nifi-extension-bundles/nifi-aws-bundle/nifi-aws-nar/target/nifi-aws-nar-2.9.0-SNAPSHOT.nar
[INFO] Signing NAR: nifi-aws-nar-2.9.0-SNAPSHOT.nar
[INFO] Signed NAR [nifi-aws-nar-2.9.0-SNAPSHOT.nar] with alias [nar-signer] from keystore [/.../nar-signing/nar-signing.p12]
...

NAR content

% unzip -l ./nifi-aws-nar/target/nifi-aws-nar-2.9.0-SNAPSHOT.nar | head
Archive:  ./nifi-aws-nar/target/nifi-aws-nar-2.9.0-SNAPSHOT.nar
  Length      Date    Time    Name
---------  ---------- -----   ----
    18178  03-06-2026 10:36   META-INF/MANIFEST.MF
    17984  03-06-2026 10:36   META-INF/SIGNER.SF
      820  03-06-2026 10:36   META-INF/SIGNER.EC
        0  02-13-2026 22:38   META-INF/
    24862  02-13-2026 22:38   META-INF/DEPENDENCIES
    11608  02-13-2026 22:38   META-INF/LICENSE
     8303  02-13-2026 22:38   META-INF/NOTICE

Verification

% jarsigner -verify -verbose -certs ./nifi-aws-nar/target/nifi-aws-nar-2.9.0-SNAPSHOT.nar

s      18178 Fri Mar 06 10:36:46 CET 2026 META-INF/MANIFEST.MF

      >>> Signer
      X.509, CN=Your Name, O=Your Organization, C=US
      Signature algorithm: SHA256withECDSA, 256-bit key
      [certificate is valid from 06/03/2026, 10:27 to 03/03/2036, 10:27]
      [Invalid certificate chain: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target]

       17984 Fri Mar 06 10:36:46 CET 2026 META-INF/SIGNER.SF
         820 Fri Mar 06 10:36:46 CET 2026 META-INF/SIGNER.EC
...

- Signed by "CN=Your Name, O=Your Organization, C=US"
    Digest algorithm: SHA-256
    Signature algorithm: SHA384withECDSA, 256-bit key

jar verified.

Manifest

% unzip -p ./nifi-aws-nar/target/nifi-aws-nar-2.9.0-SNAPSHOT.nar META-INF/MANIFEST.MF                                                   
Manifest-Version: 1.0
Created-By: Apache NiFi Nar Maven Plugin 2.4.0-SNAPSHOT
Java-Version: 21
Build-Jdk-Spec: 21
Nar-Signed-By: CN=Your Name,O=Your Organization,C=US
Nar-Id: nifi-aws-nar
Nar-Group: org.apache.nifi
Nar-Version: 2.9.0-SNAPSHOT
Nar-Dependency-Group: org.apache.nifi
Nar-Dependency-Id: nifi-aws-service-api-nar
Nar-Dependency-Version: 2.9.0-SNAPSHOT
Build-Tag: HEAD
Build-Timestamp: 2026-02-13T22:38:02Z
Clone-During-Instance-Class-Loading: false

Name: META-INF/bundled-dependencies/nifi-aws-regions-2.9.0-SNAPSHOT.jar
SHA-256-Digest: Oe0oiBk1HeuiqF2PPV2iQEMeNoWeVrhG1CP9nV0DTpQ=

Name: META-INF/bundled-dependencies/wire-grpc-client-jvm-5.2.0.jar
SHA-256-Digest: sgRBcicsGM0kr1Bsgoe1tIBSZ+/4abZtLYUhqLfyISs=

Name: META-INF/bundled-dependencies/jakarta.activation-api-2.1.4.jar
SHA-256-Digest: ydtSEAzmyKrJXMOQdflXINLlYbEfgFG4HBIa1O/9cAQ=
...

Copy link
Contributor

@exceptionfactory exceptionfactory left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for proposing this addition @pvillard31, supporting the ability to sign a NAR aligns well with general JAR signing features. I plan to take a closer look at the implementation soon.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants