Skip to content

Commit

Permalink
#784 Don't try plugins if they will not work on current protocol
Browse files Browse the repository at this point in the history
  • Loading branch information
mrotteveel committed Feb 28, 2024
1 parent 607d2e8 commit 3ece8a4
Show file tree
Hide file tree
Showing 10 changed files with 276 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
* @author Mark Rotteveel
* @since 6
*/
public class ChaCha64EncryptionPlugin implements EncryptionPlugin {
public final class ChaCha64EncryptionPlugin implements EncryptionPlugin {

private static final String CHA_CHA_CIPHER_NAME = "ChaCha";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
package org.firebirdsql.jaybird.chacha64;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.firebirdsql.gds.impl.wire.WireProtocolConstants;
import org.firebirdsql.gds.ng.wire.crypt.CryptConnectionInfo;
import org.firebirdsql.gds.ng.wire.crypt.CryptSessionConfig;
import org.firebirdsql.gds.ng.wire.crypt.EncryptionIdentifier;
import org.firebirdsql.gds.ng.wire.crypt.EncryptionPlugin;
Expand All @@ -35,7 +37,7 @@
* @author Mark Rotteveel
* @since 6
*/
public class ChaCha64EncryptionPluginSpi implements EncryptionPluginSpi {
public final class ChaCha64EncryptionPluginSpi implements EncryptionPluginSpi {

static final EncryptionIdentifier CHA_CHA_64_ID = new EncryptionIdentifier("Symmetric", "ChaCha64");
// Use registered Bouncy Castle if possible, otherwise use our own unregistered instance
Expand All @@ -52,6 +54,11 @@ public EncryptionPlugin createEncryptionPlugin(CryptSessionConfig cryptSessionCo
return new ChaCha64EncryptionPlugin(cryptSessionConfig, provider);
}

@Override
public boolean isSupported(CryptConnectionInfo cryptConnectionInfo) {
return cryptConnectionInfo.protocolVersion() >= WireProtocolConstants.PROTOCOL_VERSION16;
}

private static Provider createProvider() {
return new BouncyCastleProvider();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* Firebird Open Source JDBC Driver
*
* Distributable under LGPL license.
* You may obtain a copy of the License at http://www.gnu.org/copyleft/lgpl.html
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* LGPL License for more details.
*
* This file was created by members of the firebird development team.
* All individual contributions remain the Copyright (C) of those
* individuals. Contributors to this file are either listed here or
* can be obtained from a source control history command.
*
* All rights reserved.
*/
package org.firebirdsql.jaybird.chacha64;

import org.firebirdsql.gds.ng.wire.crypt.CryptConnectionInfo;
import org.firebirdsql.gds.ng.wire.crypt.EncryptionIdentifier;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

import static org.firebirdsql.gds.impl.wire.WireProtocolConstants.PROTOCOL_VERSION13;
import static org.firebirdsql.gds.impl.wire.WireProtocolConstants.PROTOCOL_VERSION15;
import static org.firebirdsql.gds.impl.wire.WireProtocolConstants.PROTOCOL_VERSION16;
import static org.firebirdsql.gds.impl.wire.WireProtocolConstants.PROTOCOL_VERSION18;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

/**
* @author Mark Rotteveel
*/
class ChaCha64EncryptionPluginSpiTest {

@Test
void encryptionIdentifier() {
assertEquals(new EncryptionIdentifier("Symmetric", "ChaCha64"), new ChaCha64EncryptionPluginSpi().encryptionIdentifier());
}

@ParameterizedTest
@ValueSource(ints = { PROTOCOL_VERSION16, PROTOCOL_VERSION18 })
void isSupported_true(int protocolVersion) {
assertTrue(new ChaCha64EncryptionPluginSpi().isSupported(new ConnectionInfoImpl(protocolVersion)));
}

@ParameterizedTest
// NOTE: Implementation also reports false for PROTOCOL_VERSION10 - 12, which don't support wire encryption,
// but we don't check those versions
@ValueSource(ints = { PROTOCOL_VERSION13, PROTOCOL_VERSION15 })
void isSupported_false(int protocolVersion) {
assertFalse(new ChaCha64EncryptionPluginSpi().isSupported(new ConnectionInfoImpl(protocolVersion)));
}

private record ConnectionInfoImpl(int protocolVersion) implements CryptConnectionInfo {
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Firebird Open Source JDBC Driver
*
* Distributable under LGPL license.
* You may obtain a copy of the License at http://www.gnu.org/copyleft/lgpl.html
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* LGPL License for more details.
*
* This file was created by members of the firebird development team.
* All individual contributions remain the Copyright (C) of those
* individuals. Contributors to this file are either listed here or
* can be obtained from a source control history command.
*
* All rights reserved.
*/
package org.firebirdsql.gds.ng.wire.crypt;

/**
* Details of the connection, which the SPI can use to decide if they can work.
* <p>
* NOTE: This class is currently only internal to Jaybird, consider the API as unstable.
* </p>
*
* @author Mark Rotteveel
* @since 6
*/
public interface CryptConnectionInfo {

/**
* Protocol version of the connection.
* <p>
* The protocol version is masked, so use the relevant {@code PROTOCOL_VERSIONnn} constants from
* {@link org.firebirdsql.gds.impl.wire.WireProtocolConstants} or equivalents for checks.
* </p>
*
* @return protocol version, {@code 0} means unknown (shouldn't occur normally)
*/
int protocolVersion();
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,23 @@ public interface EncryptionPluginSpi {
* @return Encryption plugin
*/
EncryptionPlugin createEncryptionPlugin(CryptSessionConfig cryptSessionConfig);

/**
* Reports if the encryption plugin can work.
* <p>
* The {@code connectionInfo} can be used to check compatibility with the connection, but other checks may be done
* as well. If the plugin expects to always work, it can simply return {@code true}.
* </p>
* <p>
* NOTE: Returning {@code true} does not express a guarantee the plugin will work, instead {@code false} expresses
* that the plugin cannot (or should not) be tried to use, because it will fail anyway.
* </p>
*
* @param cryptConnectionInfo
* information on the connection
* @return {@code true} if the SPI expects the plugin to work, {@code false} if the plugin will not work
* @since 6
*/
boolean isSupported(CryptConnectionInfo cryptConnectionInfo);

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
*/
package org.firebirdsql.gds.ng.wire.crypt.arc4;

import org.firebirdsql.gds.ng.wire.crypt.CryptConnectionInfo;
import org.firebirdsql.gds.ng.wire.crypt.CryptSessionConfig;
import org.firebirdsql.gds.ng.wire.crypt.EncryptionIdentifier;
import org.firebirdsql.gds.ng.wire.crypt.EncryptionPlugin;
Expand All @@ -42,4 +43,11 @@ public EncryptionIdentifier encryptionIdentifier() {
public EncryptionPlugin createEncryptionPlugin(CryptSessionConfig cryptSessionConfig) {
return new Arc4EncryptionPlugin(cryptSessionConfig);
}

@Override
public boolean isSupported(CryptConnectionInfo cryptConnectionInfo) {
// TODO Maybe check if ARC4 requirements are allowed by the security config?
return true;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
*/
package org.firebirdsql.gds.ng.wire.crypt.chacha;

import org.firebirdsql.gds.impl.wire.WireProtocolConstants;
import org.firebirdsql.gds.ng.wire.crypt.CryptConnectionInfo;
import org.firebirdsql.gds.ng.wire.crypt.CryptSessionConfig;
import org.firebirdsql.gds.ng.wire.crypt.EncryptionIdentifier;
import org.firebirdsql.gds.ng.wire.crypt.EncryptionPlugin;
Expand All @@ -42,4 +44,10 @@ public EncryptionIdentifier encryptionIdentifier() {
public EncryptionPlugin createEncryptionPlugin(CryptSessionConfig cryptSessionConfig) {
return new ChaChaEncryptionPlugin(cryptSessionConfig);
}

@Override
public boolean isSupported(CryptConnectionInfo cryptConnectionInfo) {
return cryptConnectionInfo.protocolVersion() >= WireProtocolConstants.PROTOCOL_VERSION16;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import org.firebirdsql.gds.ng.wire.GenericResponse;
import org.firebirdsql.gds.ng.wire.WireConnection;
import org.firebirdsql.gds.ng.wire.auth.ClientAuthBlock;
import org.firebirdsql.gds.ng.wire.crypt.CryptConnectionInfo;
import org.firebirdsql.gds.ng.wire.crypt.CryptSessionConfig;
import org.firebirdsql.gds.ng.wire.crypt.EncryptionIdentifier;
import org.firebirdsql.gds.ng.wire.crypt.EncryptionInitInfo;
Expand Down Expand Up @@ -200,16 +201,23 @@ private void tryKnownServerKeys() throws IOException, SQLException {

private Optional<EncryptionIdentifier> tryKnownServerKey(KnownServerKey.PluginSpecificData pluginSpecificData,
SQLExceptionChainBuilder chainBuilder) throws IOException {
record ConnectionInfoImpl(int protocolVersion) implements CryptConnectionInfo {
}

EncryptionIdentifier encryptionIdentifier = pluginSpecificData.encryptionIdentifier();
EncryptionPluginSpi currentEncryptionSpi =
EncryptionPluginSpi encryptionPluginSpi =
EncryptionPluginRegistry.getEncryptionPluginSpi(encryptionIdentifier);
if (currentEncryptionSpi == null) {
if (encryptionPluginSpi == null) {
log.log(TRACE, "No wire encryption plugin available for {0}", encryptionIdentifier);
return Optional.empty();
} else if (!encryptionPluginSpi.isSupported(new ConnectionInfoImpl(getConnection().getProtocolVersion()))) {
log.log(TRACE, "Wire encryption plugin {0} skipped, not supported", encryptionIdentifier);
return Optional.empty();
}

try (CryptSessionConfig cryptSessionConfig =
getCryptSessionConfig(encryptionIdentifier, pluginSpecificData.specificData())) {
EncryptionPlugin encryptionPlugin = currentEncryptionSpi.createEncryptionPlugin(cryptSessionConfig);
EncryptionPlugin encryptionPlugin = encryptionPluginSpi.createEncryptionPlugin(cryptSessionConfig);
EncryptionInitInfo encryptionInitInfo = encryptionPlugin.initializeEncryption();
if (encryptionInitInfo.isSuccess()) {
enableEncryption(encryptionInitInfo);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* Firebird Open Source JDBC Driver
*
* Distributable under LGPL license.
* You may obtain a copy of the License at http://www.gnu.org/copyleft/lgpl.html
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* LGPL License for more details.
*
* This file was created by members of the firebird development team.
* All individual contributions remain the Copyright (C) of those
* individuals. Contributors to this file are either listed here or
* can be obtained from a source control history command.
*
* All rights reserved.
*/
package org.firebirdsql.gds.ng.wire.crypt.arc4;

import org.firebirdsql.gds.ng.wire.crypt.CryptConnectionInfo;
import org.firebirdsql.gds.ng.wire.crypt.EncryptionIdentifier;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

import static org.firebirdsql.gds.impl.wire.WireProtocolConstants.PROTOCOL_VERSION13;
import static org.firebirdsql.gds.impl.wire.WireProtocolConstants.PROTOCOL_VERSION15;
import static org.firebirdsql.gds.impl.wire.WireProtocolConstants.PROTOCOL_VERSION16;
import static org.firebirdsql.gds.impl.wire.WireProtocolConstants.PROTOCOL_VERSION18;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

/**
* Tests for {@link Arc4EncryptionPluginSpi}.
*/
class Arc4EncryptionPluginSpiTest {

@Test
void encryptionIdentifier() {
assertEquals(new EncryptionIdentifier("Symmetric", "Arc4"), new Arc4EncryptionPluginSpi().encryptionIdentifier());
}

@ParameterizedTest
// NOTE: Implementation always reports true, also for PROTOCOL_VERSION10 - 12, which don't support wire encryption,
// but we don't check those versions
@ValueSource(ints = { PROTOCOL_VERSION13, PROTOCOL_VERSION15, PROTOCOL_VERSION16, PROTOCOL_VERSION18 })
void isSupported_true(int protocolVersion) {
assertTrue(new Arc4EncryptionPluginSpi().isSupported(new ConnectionInfoImpl(protocolVersion)));
}

private record ConnectionInfoImpl(int protocolVersion) implements CryptConnectionInfo {
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* Firebird Open Source JDBC Driver
*
* Distributable under LGPL license.
* You may obtain a copy of the License at http://www.gnu.org/copyleft/lgpl.html
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* LGPL License for more details.
*
* This file was created by members of the firebird development team.
* All individual contributions remain the Copyright (C) of those
* individuals. Contributors to this file are either listed here or
* can be obtained from a source control history command.
*
* All rights reserved.
*/
package org.firebirdsql.gds.ng.wire.crypt.chacha;

import org.firebirdsql.gds.ng.wire.crypt.CryptConnectionInfo;
import org.firebirdsql.gds.ng.wire.crypt.EncryptionIdentifier;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

import static org.firebirdsql.gds.impl.wire.WireProtocolConstants.PROTOCOL_VERSION13;
import static org.firebirdsql.gds.impl.wire.WireProtocolConstants.PROTOCOL_VERSION15;
import static org.firebirdsql.gds.impl.wire.WireProtocolConstants.PROTOCOL_VERSION16;
import static org.firebirdsql.gds.impl.wire.WireProtocolConstants.PROTOCOL_VERSION18;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

/**
* Tests for {@link ChaChaEncryptionPluginSpi}.
*/
class ChaChaEncryptionPluginSpiTest {

@Test
void encryptionIdentifier() {
assertEquals(new EncryptionIdentifier("Symmetric", "ChaCha"), new ChaChaEncryptionPluginSpi().encryptionIdentifier());
}

@ParameterizedTest
@ValueSource(ints = { PROTOCOL_VERSION16, PROTOCOL_VERSION18 })
void isSupported_true(int protocolVersion) {
assertTrue(new ChaChaEncryptionPluginSpi().isSupported(new ConnectionInfoImpl(protocolVersion)));
}

@ParameterizedTest
// NOTE: Implementation also reports false for PROTOCOL_VERSION10 - 12, which don't support wire encryption,
// but we don't check those versions
@ValueSource(ints = { PROTOCOL_VERSION13, PROTOCOL_VERSION15 })
void isSupported_false(int protocolVersion) {
assertFalse(new ChaChaEncryptionPluginSpi().isSupported(new ConnectionInfoImpl(protocolVersion)));
}

private record ConnectionInfoImpl(int protocolVersion) implements CryptConnectionInfo {
}

}

0 comments on commit 3ece8a4

Please sign in to comment.