@@ -934,6 +934,7 @@ enum Transport {
934934 */
935935 final class LineSenderBuilder {
936936 private static final int AUTO_FLUSH_DISABLED = 0 ;
937+ private static final String TLS_ROOTS_INSECURE_CONFIG_ERROR = "tls_roots cannot be combined with tls_verify=unsafe_off; remove tls_verify to use custom roots, or remove tls_roots to disable certificate validation" ;
937938 // close() drain timeout. Default applied at build() time. 0 or -1
938939 // means "fast close" (skip the drain entirely); any positive value
939940 // bounds the wait for ackedFsn to catch up to publishedFsn. Uses
@@ -1415,7 +1416,7 @@ public Sender build() {
14151416 }
14161417 ClientTlsConfiguration tlsConfig = null ;
14171418 if (tlsEnabled ) {
1418- assert ( trustStorePath == null ) == ( trustStorePassword == null ); //either both null or both non-null
1419+ assert trustStorePassword == null || trustStorePath != null ;
14191420 tlsConfig = new ClientTlsConfiguration (trustStorePath , trustStorePassword , tlsValidationMode == TlsValidationMode .DEFAULT ? ClientTlsConfiguration .TLS_VALIDATION_MODE_FULL : ClientTlsConfiguration .TLS_VALIDATION_MODE_NONE );
14201421 }
14211422 return AbstractLineHttpSender .createLineSender (hosts , ports , httpPath , httpClientConfiguration , tlsConfig , actualAutoFlushRows , httpToken ,
@@ -1437,7 +1438,7 @@ public Sender build() {
14371438
14381439 ClientTlsConfiguration wsTlsConfig = null ;
14391440 if (tlsEnabled ) {
1440- assert ( trustStorePath == null ) == ( trustStorePassword == null ) ;
1441+ assert trustStorePassword == null || trustStorePath != null ;
14411442 wsTlsConfig = new ClientTlsConfiguration (
14421443 trustStorePath ,
14431444 trustStorePassword ,
@@ -3573,13 +3574,12 @@ private LineSenderBuilder fromConfig(CharSequence configurationString) {
35733574 if (hosts .size () == 0 ) {
35743575 throw new LineSenderException ("addr is missing" );
35753576 }
3576- if (trustStorePath != null ) {
3577- if (trustStorePassword == null ) {
3578- throw new LineSenderException ("tls_roots was configured, but tls_roots_password is missing" );
3579- }
3580- } else if (trustStorePassword != null ) {
3577+ if (trustStorePath == null && trustStorePassword != null ) {
35813578 throw new LineSenderException ("tls_roots_password was configured, but tls_roots is missing" );
35823579 }
3580+ if (trustStorePath != null && tlsValidationMode == TlsValidationMode .INSECURE ) {
3581+ throw new LineSenderException (TLS_ROOTS_INSECURE_CONFIG_ERROR );
3582+ }
35833583 if (protocol == PROTOCOL_HTTP || protocol == PROTOCOL_WEBSOCKET ) {
35843584 if (user != null ) {
35853585 httpUsernamePassword (user , password );
@@ -3836,8 +3836,11 @@ static void validateWsConfig(ConfigView view, boolean tls) {
38363836 if (!tls && (tlsVerify != null || tlsRoots != null || tlsRootsPassword != null )) {
38373837 throw new IllegalArgumentException ("tls_verify/tls_roots/tls_roots_password require the wss:: schema" );
38383838 }
3839- if ((tlsRoots == null ) != (tlsRootsPassword == null )) {
3840- throw new IllegalArgumentException ("tls_roots and tls_roots_password must be provided together" );
3839+ if (tlsRoots == null && tlsRootsPassword != null ) {
3840+ throw new IllegalArgumentException ("tls_roots_password requires tls_roots" );
3841+ }
3842+ if (tlsRoots != null && "unsafe_off" .equals (tlsVerify )) {
3843+ throw new IllegalArgumentException (TLS_ROOTS_INSECURE_CONFIG_ERROR );
38413844 }
38423845 }
38433846
@@ -3975,6 +3978,9 @@ private void validateParameters() {
39753978 if (!tlsEnabled && tlsValidationMode != TlsValidationMode .DEFAULT ) {
39763979 throw new LineSenderException ("TLS validation disabled, but TLS was not enabled" );
39773980 }
3981+ if (trustStorePath != null && tlsValidationMode == TlsValidationMode .INSECURE ) {
3982+ throw new LineSenderException ("custom trust store cannot be combined with disabled TLS validation" );
3983+ }
39783984 if (keyId != null && bufferCapacity < MIN_BUFFER_SIZE ) {
39793985 throw new LineSenderException ("Requested buffer too small " )
39803986 .put ("[minimalCapacity=" ).put (MIN_BUFFER_SIZE )
@@ -4133,26 +4139,51 @@ private void websocket() {
41334139
41344140 public class AdvancedTlsSettings {
41354141 /**
4136- * Configure a custom truststore. This is only needed when using {@link #enableTls()} when your default
4137- * truststore does not contain certificate chain used by a server. Most users should not need it.
4142+ * Configure a PEM file containing one or more custom root certificates.
4143+ * This is only needed when using {@link #enableTls()} and the default
4144+ * trust store does not contain the certificate chain used by a server.
4145+ * Most users should not need it.
41384146 * <br>
4139- * The path can be either a path on a local filesystem. Or you can prefix it with "classpath:" to instruct
4140- * the Sender to load a trust store from a classpath.
4147+ * The path can be on the local filesystem, or it can use the
4148+ * {@code classpath:} prefix.
4149+ *
4150+ * @param pemRootsPath a path to a PEM certificate file or bundle
4151+ * @return an instance of LineSenderBuilder for further configuration
4152+ */
4153+ public LineSenderBuilder customTrustStore (String pemRootsPath ) {
4154+ return setCustomTrustStore (pemRootsPath , null );
4155+ }
4156+
4157+ /**
4158+ * Configure a password-protected JKS or PKCS#12 trust store. This is
4159+ * only needed when using {@link #enableTls()} and the default trust
4160+ * store does not contain the certificate chain used by a server.
4161+ * Most users should not need it.
4162+ * <br>
4163+ * The path can be on the local filesystem, or it can use the
4164+ * {@code classpath:} prefix.
41414165 *
41424166 * @param trustStorePath a path to a trust store.
4143- * @param trustStorePassword a password to for the truststore
4167+ * @param trustStorePassword the trust store password
41444168 * @return an instance of LineSenderBuilder for further configuration
41454169 */
41464170 public LineSenderBuilder customTrustStore (String trustStorePath , char [] trustStorePassword ) {
4171+ if (trustStorePassword == null ) {
4172+ throw new LineSenderException ("trust store password cannot be null" );
4173+ }
4174+ return setCustomTrustStore (trustStorePath , trustStorePassword );
4175+ }
4176+
4177+ private LineSenderBuilder setCustomTrustStore (String trustStorePath , char [] trustStorePassword ) {
41474178 if (LineSenderBuilder .this .trustStorePath != null ) {
41484179 throw new LineSenderException ("custom trust store was already configured " )
41494180 .put ("[path=" ).put (LineSenderBuilder .this .trustStorePath ).put ("]" );
41504181 }
41514182 if (Chars .isBlank (trustStorePath )) {
41524183 throw new LineSenderException ("trust store path cannot be empty nor null" );
41534184 }
4154- if (trustStorePassword == null ) {
4155- throw new LineSenderException ("trust store password cannot be null " );
4185+ if (tlsValidationMode == TlsValidationMode . INSECURE ) {
4186+ throw new LineSenderException ("custom trust store cannot be configured when TLS validation is disabled " );
41564187 }
41574188
41584189 LineSenderBuilder .this .trustStorePath = trustStorePath ;
@@ -4165,12 +4196,16 @@ public LineSenderBuilder customTrustStore(String trustStorePath, char[] trustSto
41654196 * This is suitable when testing self-signed certificate. It's inherently insecure and should
41664197 * never be used in a production.
41674198 * <br>
4168- * If you cannot use trusted certificate then you should prefer {@link #customTrustStore(String, char[])}
4169- * over disabling validation.
4199+ * If you cannot use a certificate in the default trust store then
4200+ * you should prefer {@link #customTrustStore(String)} or
4201+ * {@link #customTrustStore(String, char[])} over disabling validation.
41704202 *
41714203 * @return an instance of LineSenderBuilder for further configuration
41724204 */
41734205 public LineSenderBuilder disableCertificateValidation () {
4206+ if (LineSenderBuilder .this .trustStorePath != null ) {
4207+ throw new LineSenderException ("TLS validation cannot be disabled when a custom trust store is configured" );
4208+ }
41744209 LineSenderBuilder .this .tlsValidationMode = TlsValidationMode .INSECURE ;
41754210 return LineSenderBuilder .this ;
41764211 }
0 commit comments