Skip to content

Commit

Permalink
[misc] parsec fingerprint hash using either java 15 or BouncyCastle
Browse files Browse the repository at this point in the history
  • Loading branch information
rusher committed Nov 14, 2024
1 parent ce37c46 commit da6a56c
Show file tree
Hide file tree
Showing 9 changed files with 120 additions and 44 deletions.
28 changes: 28 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,18 @@
<version>2.0.3</version>
<optional>true</optional>
</dependency>
<!-- https://mvnrepository.com/artifact/org.bouncycastle/bctls-jdk18on -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk18on</artifactId>
<version>1.78.1</version>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.bouncycastle</groupId>-->
<!-- <artifactId>bcprov-jdk18on</artifactId>-->
<!-- <version>1.79</version>-->
<!-- <optional>true</optional>-->
<!-- </dependency>-->

<dependency>
<groupId>org.osgi</groupId>
Expand Down Expand Up @@ -413,6 +425,22 @@
<multiReleaseOutput>true</multiReleaseOutput>
</configuration>
</execution>
<execution>
<id>compile-java-15</id>
<phase>compile</phase>
<goals>
<goal>compile</goal>
</goals>
<configuration>
<release>15</release>
<source>15</source>
<target>15</target>
<compileSourceRoots>
<compileSourceRoot>${project.basedir}/src/main/java15</compileSourceRoot>
</compileSourceRoots>
<multiReleaseOutput>true</multiReleaseOutput>
</configuration>
</execution>
</executions>
</plugin>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -337,8 +337,9 @@ public void authenticationHandler(Credential credential, HostAddress hostAddress
throw context
.getExceptionFactory()
.create(
"Self signed certificates. Either set sslMode=trust, use password with a MitM-Proof authentication plugin or"
+ " provide server certificate to client",
"Self signed certificates. Either set sslMode=trust, use password with a"
+ " MitM-Proof authentication plugin or provide server certificate to"
+ " client",
"08000");
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ public boolean binaryProtocol() {
}

public String description() {
return "BULK: " +command;
return "BULK: " + command;
}

public void setPrepareResult(PrepareResultPacket prepareResult) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import java.security.*;
import java.security.spec.*;
import java.sql.SQLException;
import java.util.Arrays;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
Expand All @@ -22,10 +21,10 @@
public class ParsecPasswordPlugin implements AuthenticationPlugin {

private static byte[] pkcs8Ed25519header =
new byte[] {
0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x04, 0x22, 0x04,
0x20
};
new byte[] {
0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x04, 0x22, 0x04,
0x20
};
private String authenticationData;
private byte[] seed;
private byte[] salt;
Expand Down Expand Up @@ -55,7 +54,7 @@ public ParsecPasswordPlugin(String authenticationData, byte[] seed) {
* @throws IOException if socket error
*/
public ReadableByteBuf process(Writer out, Reader in, Context context)
throws SQLException, IOException {
throws SQLException, IOException {

// request ext-salt
out.writeEmptyPacket();
Expand All @@ -77,7 +76,7 @@ public ReadableByteBuf process(Writer out, Reader in, Context context)
salt = new byte[buf.readableBytes()];
buf.readBytes(salt);
char[] password =
this.authenticationData == null ? new char[0] : this.authenticationData.toCharArray();
this.authenticationData == null ? new char[0] : this.authenticationData.toCharArray();

KeyFactory ed25519KeyFactory;
Signature ed25519Signature;
Expand All @@ -93,9 +92,9 @@ public ReadableByteBuf process(Writer out, Reader in, Context context)
ed25519Signature = Signature.getInstance("Ed25519", "BC");
} catch (NoSuchAlgorithmException | NoSuchProviderException ee) {
throw new SQLException(
"Parsec authentication not available. Either use Java 15+ or add BouncyCastle"
+ " dependency",
e);
"Parsec authentication not available. Either use Java 15+ or add BouncyCastle"
+ " dependency",
e);
}
}

Expand All @@ -107,23 +106,14 @@ public ReadableByteBuf process(Writer out, Reader in, Context context)

// create a PKCS8 ED25519 private key with raw secret
PKCS8EncodedKeySpec keySpec =
new PKCS8EncodedKeySpec(combineArray(pkcs8Ed25519header, derivedKey));
new PKCS8EncodedKeySpec(combineArray(pkcs8Ed25519header, derivedKey));
PrivateKey privateKey = ed25519KeyFactory.generatePrivate(keySpec);

KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("Ed25519");
keyPairGenerator.initialize(
new NamedParameterSpec("Ed25519"), new StaticSecureRandom(derivedKey));
byte[] spki =
keyPairGenerator
.generateKeyPair()
.getPublic()
.getEncoded(); // public key in SPKI format; the last 32 bytes are the raw public key
byte[] rawPublicKey =
Arrays.copyOfRange(spki, spki.length - 32, spki.length); // 32 bytes raw public key
byte[] rawPublicKey = ParsecPasswordPluginTool.process(derivedKey);

hash =
combineArray(
combineArray(new byte[] {(byte) 'P', (byte) iterations}, salt), rawPublicKey);
combineArray(
combineArray(new byte[] {(byte) 'P', (byte) iterations}, salt), rawPublicKey);

// generate client nonce
byte[] clientScramble = new byte[32];
Expand All @@ -143,27 +133,15 @@ public ReadableByteBuf process(Writer out, Reader in, Context context)
return in.readReusablePacket();

} catch (NoSuchAlgorithmException
| InvalidKeySpecException
| InvalidKeyException
| InvalidAlgorithmParameterException
| SignatureException e) {
| InvalidKeySpecException
| InvalidKeyException
| InvalidAlgorithmParameterException
| SignatureException e) {
// not expected
throw new SQLException("Error during parsec authentication", e);
}
}

private class StaticSecureRandom extends SecureRandom {
private byte[] privateKey;

public StaticSecureRandom(byte[] privateKey) {
this.privateKey = privateKey;
}

public void nextBytes(byte[] bytes) {
System.arraycopy(privateKey, 0, bytes, 0, privateKey.length);
}
}

public boolean isMitMProof() {
return true;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
// Copyright (c) 2012-2014 Monty Program Ab
// Copyright (c) 2015-2024 MariaDB Corporation Ab
package org.mariadb.jdbc.plugin.authentication.standard;

import java.io.IOException;
import java.security.*;
import java.sql.SQLException;
import org.bouncycastle.crypto.params.Ed25519PrivateKeyParameters;
import org.bouncycastle.crypto.params.Ed25519PublicKeyParameters;

/** Parsec password plugin utility */
public class ParsecPasswordPluginTool {

public static byte[] process(byte[] rawPrivateKey)
throws SQLException,
IOException,
InvalidAlgorithmParameterException,
NoSuchAlgorithmException {
Ed25519PrivateKeyParameters privateKeyRebuild =
new Ed25519PrivateKeyParameters(rawPrivateKey, 0);
Ed25519PublicKeyParameters publicKeyRebuild = privateKeyRebuild.generatePublicKey();
return publicKeyRebuild.getEncoded();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

import java.io.*;
import java.net.URI;
import java.net.URL;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// SPDX-License-Identifier: LGPL-2.1-or-later
// Copyright (c) 2012-2014 Monty Program Ab
// Copyright (c) 2015-2024 MariaDB Corporation Ab
package org.mariadb.jdbc.plugin.authentication.standard;

import java.io.IOException;
import java.security.*;
import java.security.spec.NamedParameterSpec;
import java.sql.SQLException;
import java.util.Arrays;

/** Parsec password plugin utility*/
public class ParsecPasswordPluginTool {

public static byte[] process(byte[] rawPrivateKey)
throws SQLException, IOException, InvalidAlgorithmParameterException, NoSuchAlgorithmException {

KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("Ed25519");
keyPairGenerator.initialize(NamedParameterSpec.ED25519, new StaticSecureRandom(rawPrivateKey));

// public key in SPKI format; the last 32 bytes are the raw public key
byte[] spki =
keyPairGenerator
.generateKeyPair()
.getPublic()
.getEncoded();
byte[] rawPublicKey =
Arrays.copyOfRange(spki, spki.length - 32, spki.length);
return rawPublicKey;
}

private static class StaticSecureRandom extends SecureRandom {
private byte[] privateKey;

public StaticSecureRandom(byte[] privateKey) {
this.privateKey = privateKey;
}

public void nextBytes(byte[] bytes) {
System.arraycopy(privateKey, 0, bytes, 0, privateKey.length);
}
}
}
2 changes: 2 additions & 0 deletions src/main/java9/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@
requires transitive java.naming;
requires transitive java.security.jgss;
requires transitive jdk.net;

requires static waffle.jna;
requires static software.amazon.awssdk.services.rds;
requires static software.amazon.awssdk.regions;
requires static software.amazon.awssdk.auth;
requires static com.sun.jna;
requires static com.sun.jna.platform;
requires static org.slf4j;
requires static org.bouncycastle.pkix;

exports org.mariadb.jdbc;
exports org.mariadb.jdbc.client;
Expand Down
2 changes: 1 addition & 1 deletion src/test/java/org/mariadb/jdbc/integration/SslTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -615,7 +615,7 @@ public void trustStoreParameter() throws Throwable {
if (caCertPath != null) {
try (InputStream inStream2 = new File(caCertPath).toURI().toURL().openStream()) {
CertificateFactory cf2 = CertificateFactory.getInstance("X.509");
Collection<? extends Certificate> caCertList = cf.generateCertificates(inStream);
Collection<? extends Certificate> caCertList = cf2.generateCertificates(inStream2);
for (Iterator<? extends Certificate> iter = caCertList.iterator(); iter.hasNext(); ) {
certs.add(iter.next());
}
Expand Down

0 comments on commit da6a56c

Please sign in to comment.