Skip to content

Commit

Permalink
[Fix] Handle bouncy castle is not thread safe
Browse files Browse the repository at this point in the history
  • Loading branch information
eitch committed Jul 12, 2024
1 parent 128d95c commit 5a78c7a
Showing 1 changed file with 38 additions and 6 deletions.
44 changes: 38 additions & 6 deletions utils/src/main/java/li/strolch/utils/SmtpMailer.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,19 @@
import jakarta.mail.*;
import jakarta.mail.internet.*;
import li.strolch.utils.dbc.DBC;
import org.bouncycastle.openpgp.*;
import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPublicKeyRing;
import org.bouncycastle.openpgp.PGPSecretKey;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.util.io.Streams;
import org.pgpainless.PGPainless;
import org.pgpainless.algorithm.DocumentSignatureType;
import org.pgpainless.algorithm.HashAlgorithm;
import org.pgpainless.algorithm.SymmetricKeyAlgorithm;
import org.pgpainless.encryption_signing.*;
import org.pgpainless.key.SubkeyIdentifier;
import org.pgpainless.encryption_signing.EncryptionOptions;
import org.pgpainless.encryption_signing.EncryptionStream;
import org.pgpainless.encryption_signing.ProducerOptions;
import org.pgpainless.encryption_signing.SigningOptions;
import org.pgpainless.key.protection.SecretKeyRingProtector;
import org.pgpainless.key.protection.UnlockSecretKey;
import org.pgpainless.util.Passphrase;
Expand All @@ -25,7 +29,8 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

import static java.nio.charset.StandardCharsets.UTF_8;
import static java.text.MessageFormat.format;
Expand Down Expand Up @@ -79,12 +84,16 @@ public class SmtpMailer {

private static SmtpMailer instance;

private final ReentrantLock lock = new ReentrantLock();

/**
* <p>
* Initializes the SMTP Mailer with the given properties.
* </p>
*
* @param properties the properties to be used to initialize the mailer
*
* @return this instance
*/
public static SmtpMailer init(Properties properties) {
instance = new SmtpMailer(properties);
Expand All @@ -104,7 +113,7 @@ public static SmtpMailer init(Properties properties) {
* @param username the username for connection authorization
* @param password the password for connection authorization
*
* @return
* @return this instance
*/
public static SmtpMailer init(String fromAddress, String host, int port, boolean auth, boolean startTls,
String username, String password) {
Expand Down Expand Up @@ -398,6 +407,14 @@ protected void attachEncryptedFile(String attachment, String fileName, Multipart

protected String sign(String plainText) {
try {
// locking is required, as key rings are not thread safe
// can be removed in a future version, when bouncy castle is thread safe
// https://github.com/pgpainless/pgpainless/issues/443
// https://github.com/bcgit/bc-java/issues/1379
// https://github.com/bcgit/bc-java/pull/1383
if (!this.lock.tryLock(10, TimeUnit.SECONDS))
throw new IllegalStateException("Failed to acquired lock in 10s!");

SigningOptions signingOptions = new SigningOptions()
.addDetachedSignature(
SecretKeyRingProtector.unlockAnyKeyWith(new Passphrase(this.signingKeyPassword)),
Expand All @@ -414,13 +431,24 @@ protected String sign(String plainText) {
encryptionStream.close();

return signatureResult.toString(UTF_8);
} catch (InterruptedException e) {
throw new IllegalStateException("Interrupted while waiting to lock", e);
} catch (Exception e) {
throw new IllegalStateException("Failed to sign plain text!", e);
} finally {
this.lock.unlock();
}
}

protected String signAndEncrypt(String plainText) {
try {
// locking is required, as key rings are not thread safe
// can be removed in a future version, when bouncy castle is thread safe
// https://github.com/pgpainless/pgpainless/issues/443
// https://github.com/bcgit/bc-java/issues/1379
// https://github.com/bcgit/bc-java/pull/1383
if (!this.lock.tryLock(10, TimeUnit.SECONDS))
throw new IllegalStateException("Failed to acquired lock in 10s!");

ByteArrayOutputStream signatureResult = new ByteArrayOutputStream();
EncryptionStream encryptionStream = PGPainless
Expand All @@ -435,8 +463,12 @@ protected String signAndEncrypt(String plainText) {
encryptionStream.close();

return signatureResult.toString(UTF_8);
} catch (InterruptedException e) {
throw new IllegalStateException("Interrupted while waiting to lock", e);
} catch (Exception e) {
throw new IllegalStateException("Failed to encrypt and sign plain text!", e);
} finally {
this.lock.unlock();
}
}

Expand Down

0 comments on commit 5a78c7a

Please sign in to comment.