mirror of https://github.com/apache/nifi.git
NIFI-888 EncryptContent for PGP Leaks File Handles.
Closes InputStreams created to read the public keys for PGP encryption and several other streams involved in PGP encryptiong. This prevents NiFi from leaking file handles on every validate call or encryption attempt in the EncryptContent processor.
This commit is contained in:
parent
df1066d2ed
commit
b30fbe1f3b
|
@ -85,49 +85,61 @@ public class OpenPGPKeyBasedEncryptor implements Encryptor {
|
||||||
/*
|
/*
|
||||||
* Validate secret keyring passphrase
|
* Validate secret keyring passphrase
|
||||||
*/
|
*/
|
||||||
public static boolean validateKeyring(String provider, String secretKeyringFile, char[] passphrase) throws IOException,
|
public static boolean validateKeyring(String provider,
|
||||||
|
String secretKeyringFile, char[] passphrase) throws IOException,
|
||||||
PGPException, NoSuchProviderException {
|
PGPException, NoSuchProviderException {
|
||||||
PGPSecretKeyRingCollection pgpsec = new PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(Files.newInputStream(Paths
|
try (InputStream fin = Files.newInputStream(Paths
|
||||||
.get(secretKeyringFile))));
|
.get(secretKeyringFile))) {
|
||||||
Iterator ringit = pgpsec.getKeyRings();
|
try (InputStream pin = PGPUtil.getDecoderStream(fin)) {
|
||||||
while (ringit.hasNext()) {
|
PGPSecretKeyRingCollection pgpsec = new PGPSecretKeyRingCollection(
|
||||||
PGPSecretKeyRing secretkeyring = (PGPSecretKeyRing) ringit.next();
|
pin);
|
||||||
PGPSecretKey secretkey = secretkeyring.getSecretKey();
|
Iterator ringit = pgpsec.getKeyRings();
|
||||||
secretkey.extractPrivateKey(passphrase, provider);
|
while (ringit.hasNext()) {
|
||||||
return true;
|
PGPSecretKeyRing secretkeyring = (PGPSecretKeyRing) ringit
|
||||||
|
.next();
|
||||||
|
PGPSecretKey secretkey = secretkeyring.getSecretKey();
|
||||||
|
secretkey.extractPrivateKey(passphrase, provider);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get the public key for a specific user id from a keyring.
|
* Get the public key for a specific user id from a keyring.
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
public static PGPPublicKey getPublicKey(String userId, String publicKeyring) throws IOException, PGPException {
|
public static PGPPublicKey getPublicKey(String userId, String publicKeyring)
|
||||||
|
throws IOException, PGPException {
|
||||||
PGPPublicKey pubkey = null;
|
PGPPublicKey pubkey = null;
|
||||||
PGPPublicKeyRingCollection pgppub = new
|
try (InputStream fin = Files.newInputStream(Paths.get(publicKeyring))) {
|
||||||
PGPPublicKeyRingCollection(PGPUtil.getDecoderStream(Files.newInputStream(Paths.get(publicKeyring))));
|
try (InputStream pin = PGPUtil.getDecoderStream(fin)) {
|
||||||
|
PGPPublicKeyRingCollection pgppub = new PGPPublicKeyRingCollection(
|
||||||
|
pin);
|
||||||
|
|
||||||
Iterator ringit = pgppub.getKeyRings();
|
Iterator ringit = pgppub.getKeyRings();
|
||||||
while (ringit.hasNext()) {
|
while (ringit.hasNext()) {
|
||||||
PGPPublicKeyRing kring = (PGPPublicKeyRing) ringit.next();
|
PGPPublicKeyRing kring = (PGPPublicKeyRing) ringit.next();
|
||||||
|
|
||||||
Iterator keyit = kring.getPublicKeys();
|
Iterator keyit = kring.getPublicKeys();
|
||||||
while (keyit.hasNext()) {
|
while (keyit.hasNext()) {
|
||||||
pubkey = (PGPPublicKey) keyit.next();
|
pubkey = (PGPPublicKey) keyit.next();
|
||||||
boolean userIdMatch = false;
|
boolean userIdMatch = false;
|
||||||
|
|
||||||
Iterator userit = pubkey.getUserIDs();
|
Iterator userit = pubkey.getUserIDs();
|
||||||
while (userit.hasNext()) {
|
while (userit.hasNext()) {
|
||||||
String id = userit.next().toString();
|
String id = userit.next().toString();
|
||||||
if (id.contains(userId)) {
|
if (id.contains(userId)) {
|
||||||
userIdMatch = true;
|
userIdMatch = true;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pubkey.isEncryptionKey() && userIdMatch) {
|
||||||
|
return pubkey;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (pubkey.isEncryptionKey() && userIdMatch) {
|
|
||||||
return pubkey;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
@ -139,75 +151,88 @@ public class OpenPGPKeyBasedEncryptor implements Encryptor {
|
||||||
private String secretKeyring;
|
private String secretKeyring;
|
||||||
private char[] passphrase;
|
private char[] passphrase;
|
||||||
|
|
||||||
OpenPGPDecryptCallback(final String provider, final String keyring, final char[] passphrase) {
|
OpenPGPDecryptCallback(final String provider, final String keyring,
|
||||||
|
final char[] passphrase) {
|
||||||
this.provider = provider;
|
this.provider = provider;
|
||||||
this.secretKeyring = keyring;
|
this.secretKeyring = keyring;
|
||||||
this.passphrase = passphrase;
|
this.passphrase = passphrase;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void process(InputStream in, OutputStream out) throws IOException {
|
public void process(InputStream in, OutputStream out)
|
||||||
InputStream pgpin = PGPUtil.getDecoderStream(in);
|
throws IOException {
|
||||||
PGPObjectFactory pgpFactory = new PGPObjectFactory(pgpin);
|
try (InputStream pgpin = PGPUtil.getDecoderStream(in)) {
|
||||||
|
PGPObjectFactory pgpFactory = new PGPObjectFactory(pgpin);
|
||||||
|
|
||||||
Object obj = pgpFactory.nextObject();
|
Object obj = pgpFactory.nextObject();
|
||||||
if (!(obj instanceof PGPEncryptedDataList)) {
|
|
||||||
obj = pgpFactory.nextObject();
|
|
||||||
if (!(obj instanceof PGPEncryptedDataList)) {
|
if (!(obj instanceof PGPEncryptedDataList)) {
|
||||||
throw new ProcessException("Invalid OpenPGP data");
|
obj = pgpFactory.nextObject();
|
||||||
}
|
if (!(obj instanceof PGPEncryptedDataList)) {
|
||||||
}
|
|
||||||
PGPEncryptedDataList encList = (PGPEncryptedDataList) obj;
|
|
||||||
|
|
||||||
PGPSecretKeyRingCollection pgpSecretKeyring;
|
|
||||||
try {
|
|
||||||
// open secret keyring file
|
|
||||||
pgpSecretKeyring = new PGPSecretKeyRingCollection(PGPUtil.getDecoderStream(Files
|
|
||||||
.newInputStream(Paths.get(secretKeyring))));
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new ProcessException("Invalid secret keyring - " + e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
PGPPrivateKey privateKey = null;
|
|
||||||
PGPPublicKeyEncryptedData encData = null;
|
|
||||||
|
|
||||||
// find the secret key in the encrypted data
|
|
||||||
Iterator it = encList.getEncryptedDataObjects();
|
|
||||||
while (privateKey == null && it.hasNext()) {
|
|
||||||
obj = it.next();
|
|
||||||
if (!(obj instanceof PGPPublicKeyEncryptedData)) {
|
|
||||||
throw new ProcessException("Invalid OpenPGP data");
|
throw new ProcessException("Invalid OpenPGP data");
|
||||||
}
|
}
|
||||||
encData = (PGPPublicKeyEncryptedData) obj;
|
}
|
||||||
PGPSecretKey secretkey = pgpSecretKeyring.getSecretKey(encData.getKeyID());
|
PGPEncryptedDataList encList = (PGPEncryptedDataList) obj;
|
||||||
if (secretkey != null) {
|
|
||||||
privateKey = secretkey.extractPrivateKey(passphrase, provider);
|
PGPSecretKeyRingCollection pgpSecretKeyring;
|
||||||
|
try {
|
||||||
|
// open secret keyring file
|
||||||
|
pgpSecretKeyring = new PGPSecretKeyRingCollection(
|
||||||
|
PGPUtil.getDecoderStream(Files.newInputStream(Paths
|
||||||
|
.get(secretKeyring))));
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ProcessException("Invalid secret keyring - "
|
||||||
|
+ e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
PGPPrivateKey privateKey = null;
|
||||||
|
PGPPublicKeyEncryptedData encData = null;
|
||||||
|
|
||||||
|
// find the secret key in the encrypted data
|
||||||
|
Iterator it = encList.getEncryptedDataObjects();
|
||||||
|
while (privateKey == null && it.hasNext()) {
|
||||||
|
obj = it.next();
|
||||||
|
if (!(obj instanceof PGPPublicKeyEncryptedData)) {
|
||||||
|
throw new ProcessException("Invalid OpenPGP data");
|
||||||
|
}
|
||||||
|
encData = (PGPPublicKeyEncryptedData) obj;
|
||||||
|
PGPSecretKey secretkey = pgpSecretKeyring
|
||||||
|
.getSecretKey(encData.getKeyID());
|
||||||
|
if (secretkey != null) {
|
||||||
|
privateKey = secretkey.extractPrivateKey(
|
||||||
|
passphrase, provider);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (privateKey == null) {
|
||||||
|
throw new ProcessException(
|
||||||
|
"Secret keyring does not contain the key required to decrypt");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (privateKey == null) {
|
|
||||||
throw new ProcessException("Secret keyring does not contain the key required to decrypt");
|
|
||||||
}
|
|
||||||
|
|
||||||
InputStream clearData = encData.getDataStream(privateKey, provider);
|
try (InputStream clearData = encData.getDataStream(
|
||||||
PGPObjectFactory clearFactory = new PGPObjectFactory(clearData);
|
privateKey, provider)) {
|
||||||
|
PGPObjectFactory clearFactory = new PGPObjectFactory(
|
||||||
|
clearData);
|
||||||
|
|
||||||
obj = clearFactory.nextObject();
|
obj = clearFactory.nextObject();
|
||||||
if (obj instanceof PGPCompressedData) {
|
if (obj instanceof PGPCompressedData) {
|
||||||
PGPCompressedData compData = (PGPCompressedData) obj;
|
PGPCompressedData compData = (PGPCompressedData) obj;
|
||||||
clearFactory = new PGPObjectFactory(compData.getDataStream());
|
clearFactory = new PGPObjectFactory(
|
||||||
obj = clearFactory.nextObject();
|
compData.getDataStream());
|
||||||
}
|
obj = clearFactory.nextObject();
|
||||||
PGPLiteralData literal = (PGPLiteralData) obj;
|
}
|
||||||
|
PGPLiteralData literal = (PGPLiteralData) obj;
|
||||||
|
|
||||||
InputStream lis = literal.getInputStream();
|
try (InputStream lis = literal.getInputStream()) {
|
||||||
final byte[] buffer = new byte[4096];
|
final byte[] buffer = new byte[4096];
|
||||||
int len;
|
int len;
|
||||||
while ((len = lis.read(buffer)) >= 0) {
|
while ((len = lis.read(buffer)) >= 0) {
|
||||||
out.write(buffer, 0, len);
|
out.write(buffer, 0, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new ProcessException(e.getMessage());
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
|
||||||
throw new ProcessException(e.getMessage());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -231,43 +256,53 @@ public class OpenPGPKeyBasedEncryptor implements Encryptor {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void process(InputStream in, OutputStream out) throws IOException {
|
public void process(InputStream in, OutputStream out)
|
||||||
|
throws IOException {
|
||||||
PGPPublicKey publicKey;
|
PGPPublicKey publicKey;
|
||||||
try {
|
try {
|
||||||
publicKey = getPublicKey(userId, publicKeyring);
|
publicKey = getPublicKey(userId, publicKeyring);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new ProcessException("Invalid public keyring - " + e.getMessage());
|
throw new ProcessException("Invalid public keyring - "
|
||||||
|
+ e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
SecureRandom secureRandom = SecureRandom.getInstance(SECURE_RANDOM_ALGORITHM);
|
SecureRandom secureRandom = SecureRandom
|
||||||
|
.getInstance(SECURE_RANDOM_ALGORITHM);
|
||||||
|
|
||||||
OutputStream output = out;
|
OutputStream output = out;
|
||||||
if (EncryptContent.isPGPArmoredAlgorithm(algorithm)) {
|
if (EncryptContent.isPGPArmoredAlgorithm(algorithm)) {
|
||||||
output = new ArmoredOutputStream(out);
|
output = new ArmoredOutputStream(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
PGPEncryptedDataGenerator encGenerator = new PGPEncryptedDataGenerator(PGPEncryptedData.CAST5, false,
|
PGPEncryptedDataGenerator encGenerator = new PGPEncryptedDataGenerator(
|
||||||
secureRandom, provider);
|
PGPEncryptedData.CAST5, false, secureRandom, provider);
|
||||||
encGenerator.addMethod(publicKey);
|
encGenerator.addMethod(publicKey);
|
||||||
OutputStream encOut = encGenerator.open(output, new byte[65536]);
|
try (OutputStream encOut = encGenerator.open(output,
|
||||||
|
new byte[65536])) {
|
||||||
|
|
||||||
PGPCompressedDataGenerator compData = new PGPCompressedDataGenerator(PGPCompressedData.ZIP, Deflater.BEST_SPEED);
|
PGPCompressedDataGenerator compData = new PGPCompressedDataGenerator(
|
||||||
OutputStream compOut = compData.open(encOut, new byte[65536]);
|
PGPCompressedData.ZIP, Deflater.BEST_SPEED);
|
||||||
|
try (OutputStream compOut = compData.open(encOut,
|
||||||
|
new byte[65536])) {
|
||||||
|
|
||||||
PGPLiteralDataGenerator literal = new PGPLiteralDataGenerator();
|
PGPLiteralDataGenerator literal = new PGPLiteralDataGenerator();
|
||||||
OutputStream literalOut = literal.open(compOut, PGPLiteralData.BINARY, filename, new Date(), new byte[65536]);
|
try (OutputStream literalOut = literal.open(compOut,
|
||||||
|
PGPLiteralData.BINARY, filename, new Date(),
|
||||||
|
new byte[65536])) {
|
||||||
|
|
||||||
final byte[] buffer = new byte[4096];
|
final byte[] buffer = new byte[4096];
|
||||||
int len;
|
int len;
|
||||||
while ((len = in.read(buffer)) >= 0) {
|
while ((len = in.read(buffer)) >= 0) {
|
||||||
literalOut.write(buffer, 0, len);
|
literalOut.write(buffer, 0, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (EncryptContent.isPGPArmoredAlgorithm(algorithm)) {
|
||||||
|
output.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
literalOut.close();
|
|
||||||
compOut.close();
|
|
||||||
encOut.close();
|
|
||||||
output.close();
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new ProcessException(e.getMessage());
|
throw new ProcessException(e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue