NIFI-5346 Introduces new PGP controller service and PGP processors.#4077
NIFI-5346 Introduces new PGP controller service and PGP processors.#4077natural wants to merge 8 commits intoapache:masterfrom
Conversation
...ork-core/src/main/java/org/apache/nifi/controller/repository/StandardProvenanceReporter.java
Outdated
Show resolved
Hide resolved
...ork-core/src/main/java/org/apache/nifi/controller/repository/StandardProvenanceReporter.java
Outdated
Show resolved
Hide resolved
...d-processors/src/main/java/org/apache/nifi/processors/standard/pgp/AbstractProcessorPGP.java
Outdated
Show resolved
Hide resolved
...d-processors/src/main/java/org/apache/nifi/processors/standard/pgp/AbstractProcessorPGP.java
Outdated
Show resolved
Hide resolved
...d-processors/src/main/java/org/apache/nifi/processors/standard/pgp/AbstractProcessorPGP.java
Outdated
Show resolved
Hide resolved
...d-processors/src/main/java/org/apache/nifi/processors/standard/pgp/AbstractProcessorPGP.java
Outdated
Show resolved
Hide resolved
...d-processors/src/main/java/org/apache/nifi/processors/standard/pgp/AbstractProcessorPGP.java
Outdated
Show resolved
Hide resolved
...d-processors/src/main/java/org/apache/nifi/processors/standard/pgp/AbstractProcessorPGP.java
Outdated
Show resolved
Hide resolved
...dard-processors/src/main/java/org/apache/nifi/processors/standard/pgp/DecryptContentPGP.java
Outdated
Show resolved
Hide resolved
...dard-processors/src/main/java/org/apache/nifi/processors/standard/pgp/DecryptContentPGP.java
Outdated
Show resolved
Hide resolved
...dard-processors/src/main/java/org/apache/nifi/processors/standard/pgp/DecryptContentPGP.java
Outdated
Show resolved
Hide resolved
| /** | ||
| * This class defines an implementation of {@link PGPService} suitable for use with the PGP processors in this package. | ||
| * | ||
| * In addition to basic Controller Service functionality this class exposes high-level, stream-based cryptographic operations |
There was a problem hiding this comment.
I think I was unclear in our previous conversations. I was imagining an (internal) service which provided these high-level functions, separate from the NiFi interface SpecificControllerService and class StandardSpecificControllerService implements SpecificControllerService (see SSLContextService and StandardSSLContextService/RestrictedStandardSSLContextService or KerberosCredentialsService/KeytabCredentialsService for examples).
This would provide the following benefits:
- The
PGPServicewould provide easy-to-consume and safe-to-use PGP operations to NiFi code. - The PGP-specific logic would only be here, making upgrades/change-of-library/etc. work isolated and contained.
- The
PGPKeyMaterialService(example name) would have aStandardPGPKeyMaterialServiceimplementation which defined the necessaryPropertyDescriptorsand logic for parsing the low-level values out of the NiFi concepts of PD/AllowableValueinto Java types. These parameters to the cryptographic operations I believe you have encapsulated in the variousEncryptOptions, etc. classes. I would expect these to share a common marker interface likePGPOptions. - The parsed parameters would be extracted from the controller service implementation within the respective processor implementations in
#onTrigger()and passed to thePGPServiceinstance to perform the actual cryptographic operations.
In my view, controller services and processors should both be minimal in the sense that they are wrappers/adaptors for fitting the actual behavior/logic into the NiFi framework, while the logic, especially unrelated to NiFi-specific concepts, should be encapsulated on its own to provide clear separation of concerns. This is demonstrated (incompletely and not as cleanly as I would like) in EncryptContent which delegates the actual operations to OpenPGPKeyBasedEncryptor, OpenPGPPasswordBasedEncryptor, KeyBasedEncryptor, and PasswordBasedEncryptor.
There was a problem hiding this comment.
This will require a few hours to re-organize, but I don't foresee any real difficulty. The controller class is clearly doing double-duty and the behaviors are cleanly marked and clearly separable. If history is any guide, the packaging and module-making parts will be the most difficult. Do you have any suggested module layout in mind?
There was a problem hiding this comment.
For now I've refactored these methods into classes/interfaces into a new package org.apache.nifi.security.pgp; please advise on that choice when you can.
There was a problem hiding this comment.
I think that package is appropriate. The pure cryptographic services can go in the nifi-security-utils module. The module already includes BouncyCastle as a dependency so you should not need to modify LICENSE or NOTICE.
There was a problem hiding this comment.
I've extracted the (internal) service you mentioned to an interface called PGPOperator and a standard implementation called StandardPGPOperator, both in package org.apache.nifi.security.pgp and module nifi-security-utils.
I picked "operator" to avoid confusion with "service" and "controller". "PGPUtil" or similar wasn't considered because we have (at least) two of those already.
NB the package placement of the Controller Service interfaces; this was intentional but I'm not certain if it's optimal.
...d-processors/src/main/java/org/apache/nifi/processors/standard/pgp/PGPControllerService.java
Outdated
Show resolved
Hide resolved
...d-processors/src/main/java/org/apache/nifi/processors/standard/pgp/PGPControllerService.java
Outdated
Show resolved
Hide resolved
...d-processors/src/main/java/org/apache/nifi/processors/standard/pgp/PGPControllerService.java
Show resolved
Hide resolved
...d-processors/src/main/java/org/apache/nifi/processors/standard/pgp/PGPControllerService.java
Outdated
Show resolved
Hide resolved
...d-processors/src/main/java/org/apache/nifi/processors/standard/pgp/PGPControllerService.java
Outdated
Show resolved
Hide resolved
...d-processors/src/main/java/org/apache/nifi/processors/standard/pgp/PGPControllerService.java
Outdated
Show resolved
Hide resolved
...d-processors/src/main/java/org/apache/nifi/processors/standard/pgp/PGPControllerService.java
Outdated
Show resolved
Hide resolved
...d-processors/src/main/java/org/apache/nifi/processors/standard/pgp/PGPControllerService.java
Outdated
Show resolved
Hide resolved
...d-processors/src/main/java/org/apache/nifi/processors/standard/pgp/PGPControllerService.java
Outdated
Show resolved
Hide resolved
...d-processors/src/main/java/org/apache/nifi/processors/standard/pgp/PGPControllerService.java
Outdated
Show resolved
Hide resolved
24dfad9 to
749e259
Compare
|
I also don't see any changes to the existing |
3db88b3 to
bc987af
Compare
| * @param signature receives signature | ||
| * @param options used to configure sign operation | ||
| */ | ||
| void sign(InputStream input, OutputStream signature, SignOptions options) throws IOException, PGPException; |
There was a problem hiding this comment.
Thank you for doing all this work! I am trying to sign files to be verified by another party (e.g. by pgp). I suppose this is good for generating detached signatures as an attribute. What about modifying the flowfile to be the signed version (non-detached) (i.e. gpg --output doc.sig --sign doc)? Are there plans for a SignContentPGP processor? If not, how could you use this processor to later combine the signature with another file.
There was a problem hiding this comment.
There are no plans for a SignContentPGPProcessor of which I'm aware, but it sounds like a good addition; could you open a jira ticket for the feature if/when this PR is merged?
There was a problem hiding this comment.
I created my ticket NIFI-7322. Do you mind taking a look at it and fixing it if you see any issues, as this is my first time submitting a ticket for this project.
| interface SignOptions { | ||
| int getHashAlgorithm(); | ||
| PGPPrivateKey getPrivateKey(); | ||
| } |
There was a problem hiding this comment.
Should there be options for clear text signing (similar to gpg --clearsign)?
There was a problem hiding this comment.
Perhaps yes, and I think that's the case when the sign+verify processors allow for additional types of encoding. As it stands, the algorithm selection is separate from the (fixed, hex) encoding.
|
|
||
| for (final PGPPublicKeyRing ring : rings) { | ||
| for (final PGPPublicKey key : ring) { | ||
| for (final Iterator<String> it = key.getUserIDs(); it.hasNext(); ) { |
There was a problem hiding this comment.
When using a ECDSA/ECDH pgp key, the public key is created with ECDSA as primary, and ECDH as a sub key. This method fails to detect the ECDH sub key as it does not contain a user id; which means that the keys hash only contains the signing key, not the encryption key. This then fails at ln 742.
Steps to repeat
gpg --full-gen-key --expert
Please select what kind of key you want:
(1) RSA and RSA (default)
(2) DSA and Elgamal
(3) DSA (sign only)
(4) RSA (sign only)
(7) DSA (set your own capabilities)
(8) RSA (set your own capabilities)
(9) ECC and ECC
(10) ECC (sign only)
(11) ECC (set your own capabilities)
(13) Existing key
(14) Existing key from card
Your selection? 9
Please select which elliptic curve you want:
(1) Curve 25519
(3) NIST P-256
(4) NIST P-384
(5) NIST P-521
(9) secp256k1
Your selection? 4
Please specify how long the key should be valid.
0 = key does not expire
= key expires in n days
w = key expires in n weeks
m = key expires in n months
y = key expires in n years
Key is valid for? (0) 0
Key does not expire at all
Is this correct? (y/N) y
gpg --export --armor --output public-key.asc
|
|
||
| for (final PGPSecretKeyRing ring : rings) { | ||
| for (final PGPSecretKey secretKey : ring) { | ||
| for (final Iterator<String> it = secretKey.getUserIDs(); it.hasNext(); ) { |
There was a problem hiding this comment.
As with readPublicKeys this is not compatible with ECDSA/ECDH as the secret key for decryption is a sub key of the parent.
The following very hacky solution will detect the correct secret key, but a better solution would be to change the keys hash to also store the type of key along with the user id so that the process is less fragile
if (!secretKey.isMasterKey()) {
// search for user id from the parent of this sub key
try {
for (Iterator<PGPSignature> it = secretKey.getPublicKey().getSignatures(); it.hasNext(); ) {
PGPSignature signature = it.next();
long keyId = signature.getKeyID();
PGPSecretKey parentKey = rings.getSecretKey(keyId);
for (final Iterator<String> it2 = parentKey.getUserIDs(); it2.hasNext(); ) {
keys.put(it2.next(), secretKey);
}
}
} catch (PGPException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
|
Thanks for the additional comments @sasqnz . I believe the original author is not continuing with this effort, so I will be making a new PR for this ticket and will be sure to test the cases you raised. |
|
We're marking this PR as stale due to lack of updates in the past few months. If after another couple of weeks the stale label has not been removed this PR will be closed. This stale marker and eventual auto close does not indicate a judgement of the PR just lack of reviewer bandwidth and helps us keep the PR queue more manageable. If you would like this PR re-opened you can do so and a committer can remove the stale tag. Or you can open a new PR. Try to help review other PRs to increase PR review bandwidth which in turn helps yours. |
Introduces new PGP Controller Service and PGP Processors
Enables PGP encryption, decryption, digital signing and verification functionality; fixes bug NIFI-5346.
Also addresses or resolves NIFI-5335, NIFI-6708.
This PR replaces #4032.
In order to streamline the review of the contribution we ask you
to ensure the following steps have been taken:
For all changes:
Is there a JIRA ticket associated with this PR? Is it referenced
in the commit message?
Does your PR title start with NIFI-XXXX where XXXX is the JIRA number you are trying to resolve? Pay particular attention to the hyphen "-" character.
Has your PR been rebased against the latest commit within the target branch (typically
master)?Is your initial contribution a single, squashed commit? Additional commits in response to PR reviewer feedback should be made on this branch and pushed to allow change tracking. Do not
squashor use--forcewhen pushing to allow for clean monitoring of changes.For code changes:
mvn -Pcontrib-check clean installat the rootnififolder?LICENSEfile, including the mainLICENSEfile undernifi-assembly?NOTICEfile, including the mainNOTICEfile found undernifi-assembly?.displayNamein addition to .name (programmatic access) for each of the new properties?For documentation related changes:
Note:
Please ensure that once the PR is submitted, you check travis-ci for build issues and submit an update to your PR as soon as possible.