Bug fixes
This commit is contained in:
4
pom.xml
4
pom.xml
@@ -6,7 +6,7 @@
|
||||
|
||||
<groupId>org.openautonomousconnection</groupId>
|
||||
<artifactId>Protocol</artifactId>
|
||||
<version>1.0.0-BETA.7.6</version>
|
||||
<version>1.0.0-BETA.7.7</version>
|
||||
<organization>
|
||||
<name>Open Autonomous Connection</name>
|
||||
<url>https://open-autonomous-connection.org/</url>
|
||||
@@ -119,7 +119,7 @@
|
||||
<dependency>
|
||||
<groupId>dev.unlegitdqrk</groupId>
|
||||
<artifactId>unlegitlibrary</artifactId>
|
||||
<version>1.8.0</version>
|
||||
<version>1.8.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
|
||||
@@ -16,6 +16,7 @@ import org.openautonomousconnection.protocol.side.web.ProtocolWebServer;
|
||||
import org.openautonomousconnection.protocol.versions.v1_0_0.beta.INSRecord;
|
||||
import org.openautonomousconnection.protocol.versions.v1_0_0.beta.INSResponseStatus;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -60,7 +61,11 @@ public final class CustomServerListener extends EventListener {
|
||||
if (!server.getProtocolBridge().isRunningAsWebServer()) return;
|
||||
if (!(event.getPacket() instanceof WebRequestPacket packet)) return;
|
||||
|
||||
((ProtocolWebServer) server).onWebRequest(server.getClientByID(event.getClient().getUniqueID()), packet);
|
||||
try {
|
||||
event.getClient().sendPacket(((ProtocolWebServer) server).onWebRequest(server.getClientByID(event.getClient().getUniqueID()), packet), TransportProtocol.TCP);
|
||||
} catch (IOException e) {
|
||||
server.getProtocolBridge().getLogger().exception("Failed to send web response to client", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -129,11 +129,9 @@ public final class AuthPacket extends OACPacket {
|
||||
setResponseCode(INSResponseStatus.RESPONSE_AUTH_SUCCESS);
|
||||
|
||||
CustomConnectedClient client = protocolBridge.getProtocolServer().getClientByID(clientID);
|
||||
if (client != null) {
|
||||
client.setClientVersion(clientVersion);
|
||||
protocolBridge.getProtocolValues().eventManager.executeEvent(new S_CustomClientConnectedEvent(client));
|
||||
client.getConnection().sendPacket(new AuthPacket(protocolBridge), TransportProtocol.TCP);
|
||||
}
|
||||
client.setClientVersion(clientVersion);
|
||||
protocolBridge.getProtocolValues().eventManager.executeEvent(new S_CustomClientConnectedEvent(client));
|
||||
client.getConnection().sendPacket(new AuthPacket(protocolBridge), TransportProtocol.TCP);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -142,7 +140,12 @@ public final class AuthPacket extends OACPacket {
|
||||
boolean fromINS = objectInputStream.readBoolean();
|
||||
ProtocolVersion serverVersion = ProtocolVersion.valueOf(objectInputStream.readUTF());
|
||||
|
||||
if (fromINS) {
|
||||
if (!fromINS) {
|
||||
protocolBridge.getProtocolClient().setServerVersion(serverVersion);
|
||||
protocolBridge.getProtocolValues().eventManager.executeEvent(
|
||||
new ConnectedToProtocolServerEvent(protocolBridge.getProtocolClient())
|
||||
);
|
||||
} else {
|
||||
if (!protocolBridge.isVersionSupported(serverVersion)) {
|
||||
setResponseCode(INSResponseStatus.RESPONSE_AUTH_FAILED);
|
||||
if (protocolBridge.getProtocolClient() != null && protocolBridge.getProtocolClient().getClientINSConnection() != null) {
|
||||
@@ -159,7 +162,10 @@ public final class AuthPacket extends OACPacket {
|
||||
|
||||
if (caPem.equalsIgnoreCase("N/A")) {
|
||||
setResponseCode(INSResponseStatus.RESPONSE_AUTH_FAILED);
|
||||
} else {
|
||||
protocolBridge.getProtocolClient().getClientINSConnection().disconnect();
|
||||
return;
|
||||
}
|
||||
|
||||
byte[] caBytes = caPem.getBytes(java.nio.charset.StandardCharsets.UTF_8);
|
||||
String fp = "N/A";
|
||||
|
||||
@@ -178,45 +184,36 @@ public final class AuthPacket extends OACPacket {
|
||||
protocolBridge.getProtocolClient().getFolderStructure().publicCAFolder,
|
||||
caPrefix + ".fp");
|
||||
|
||||
|
||||
if (fpFile.exists()) {
|
||||
if (!fpFile.exists()) {
|
||||
if (!protocolBridge.getProtocolClient().trustINS(fp)) {
|
||||
setResponseCode(INSResponseStatus.RESPONSE_AUTH_FAILED);
|
||||
protocolBridge.getProtocolClient().getClientINSConnection().disconnect();
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
String existing = FileUtils.readFileLines(fpFile).getFirst();
|
||||
if (!existing.equalsIgnoreCase(fp)) {
|
||||
if (!protocolBridge.getProtocolClient().trustNewINSFingerprint(existing, fp)) {
|
||||
setResponseCode(INSResponseStatus.RESPONSE_AUTH_FAILED);
|
||||
protocolBridge.getProtocolClient().getClientINSConnection().disconnect();
|
||||
return;
|
||||
} else {
|
||||
FileUtils.writeFile(fpFile, fp + System.lineSeparator());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!protocolBridge.getProtocolClient().trustINS(fp)) {
|
||||
setResponseCode(INSResponseStatus.RESPONSE_AUTH_FAILED);
|
||||
protocolBridge.getProtocolClient().getClientINSConnection().disconnect();
|
||||
return;
|
||||
} else {
|
||||
FileUtils.writeFile(fpFile, fp + System.lineSeparator());
|
||||
}
|
||||
}
|
||||
|
||||
FileUtils.writeFile(fpFile, fp + System.lineSeparator());
|
||||
|
||||
try {
|
||||
FileUtils.writeFile(caPemFile, caPem);
|
||||
} catch (Exception exception) {
|
||||
protocolBridge.getLogger().exception("Failed to create/save ca-files", exception);
|
||||
setResponseCode(INSResponseStatus.RESPONSE_AUTH_FAILED);
|
||||
}
|
||||
}
|
||||
|
||||
protocolBridge.getProtocolClient().setInsVersion(serverVersion);
|
||||
protocolBridge.getProtocolValues().eventManager.executeEvent(
|
||||
new ConnectedToProtocolINSServerEvent(protocolBridge.getProtocolClient())
|
||||
);
|
||||
} else {
|
||||
protocolBridge.getProtocolClient().setServerVersion(serverVersion);
|
||||
protocolBridge.getProtocolValues().eventManager.executeEvent(
|
||||
new ConnectedToProtocolServerEvent(protocolBridge.getProtocolClient())
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ public abstract class ProtocolINSServer extends ProtocolCustomServer {
|
||||
java.security.MessageDigest md = java.security.MessageDigest.getInstance("SHA-256");
|
||||
String fp = java.util.HexFormat.of().formatHex(md.digest(caBytes));
|
||||
|
||||
System.out.println("CA Fingerprint: " + fp);
|
||||
getProtocolBridge().getLogger().info("CA Fingerprint: " + fp);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -120,36 +120,75 @@ public abstract class ProtocolCustomServer extends EventListener {
|
||||
trustStore.setCertificateEntry("root-ca-" + (caIndex++), caCert);
|
||||
}
|
||||
|
||||
// --- Build server key material (private key + certificate chain) ---
|
||||
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
|
||||
keyStore.load(null, null);
|
||||
|
||||
Map<String, File> keyFiles = new HashMap<>();
|
||||
Map<String, File> certFiles = new HashMap<>();
|
||||
|
||||
for (File f : FileUtils.listFiles(folderStructure.privateServerFolder, ".key", ".pem")) {
|
||||
for (File f : FileUtils.listFiles(folderStructure.privateServerFolder, ".key")) {
|
||||
if (f.getName().endsWith(".srl")) continue;
|
||||
if (!f.getName().startsWith(folderStructure.getCertPrefix())) continue;
|
||||
keyFiles.put(FileUtils.stripExt(f.getName()), f);
|
||||
}
|
||||
|
||||
String base = FileUtils.stripExt(f.getName());
|
||||
if (f.getName().endsWith(".key")) keyFiles.put(base, f);
|
||||
if (f.getName().endsWith(".pem")) certFiles.put(base, f);
|
||||
// Allow cert files in public server folder as .pem/.crt/.cer
|
||||
for (File f : FileUtils.listFiles(folderStructure.publicServerFolder, ".pem", ".crt", ".cer")) {
|
||||
if (f.getName().endsWith(".srl")) continue;
|
||||
if (!f.getName().startsWith(folderStructure.getCertPrefix())) continue;
|
||||
certFiles.put(FileUtils.stripExt(f.getName()), f);
|
||||
}
|
||||
|
||||
// Load all CA certs once (for chain building)
|
||||
List<X509Certificate> caCerts = new ArrayList<>();
|
||||
for (File caPem : FileUtils.listFiles(folderStructure.publicCAFolder, ".pem", ".crt", ".cer")) {
|
||||
if (caPem.getName().endsWith(".srl")) continue;
|
||||
if (!caPem.getName().startsWith(folderStructure.getCaPrefix())) continue;
|
||||
caCerts.add(PemUtils.loadCertificate(caPem));
|
||||
}
|
||||
|
||||
int serverIndex = 0;
|
||||
for (String base : keyFiles.keySet()) {
|
||||
File keyFile = keyFiles.get(base);
|
||||
for (Map.Entry<String, File> e : keyFiles.entrySet()) {
|
||||
String base = e.getKey();
|
||||
File keyFile = e.getValue();
|
||||
|
||||
File certFile = certFiles.get(base);
|
||||
if (certFile == null) {
|
||||
File alt = new File(folderStructure.publicServerFolder, base + ".pem");
|
||||
if (alt.exists()) certFile = alt;
|
||||
// If your naming differs between private key and public cert, log it and skip
|
||||
continue;
|
||||
}
|
||||
if (certFile == null) continue;
|
||||
|
||||
PrivateKey key = PemUtils.loadPrivateKey(keyFile);
|
||||
X509Certificate cert = PemUtils.loadCertificate(certFile);
|
||||
PrivateKey privateKey = PemUtils.loadPrivateKey(keyFile);
|
||||
X509Certificate leaf = PemUtils.loadCertificate(certFile);
|
||||
|
||||
// Build a minimal chain: leaf + issuer CA if found (or all CAs as fallback)
|
||||
List<X509Certificate> chain = new ArrayList<>();
|
||||
chain.add(leaf);
|
||||
|
||||
// Try to find matching issuer CA(s) by Subject/Issuer DN
|
||||
X509Certificate current = leaf;
|
||||
for (int depth = 0; depth < 5; depth++) {
|
||||
X509Certificate issuer = findIssuer(current, caCerts);
|
||||
if (issuer == null) break;
|
||||
chain.add(issuer);
|
||||
if (issuer.getSubjectX500Principal().equals(issuer.getIssuerX500Principal())) {
|
||||
// self-signed root reached
|
||||
break;
|
||||
}
|
||||
current = issuer;
|
||||
}
|
||||
|
||||
String alias = "server-" + (serverIndex++);
|
||||
keyStore.setKeyEntry(alias, key, keyPass, new X509Certificate[]{cert});
|
||||
keyStore.setKeyEntry(alias, privateKey, keyPass, chain.toArray(new X509Certificate[0]));
|
||||
}
|
||||
|
||||
// If still empty, fail fast with a clear error instead of handshake_failure later
|
||||
if (!keyStore.aliases().hasMoreElements()) {
|
||||
throw new IllegalStateException(
|
||||
"No server key entries loaded. Ensure private .key and public .crt/.pem names match and start with prefix "
|
||||
+ folderStructure.getCertPrefix()
|
||||
);
|
||||
}
|
||||
|
||||
network = new NetworkServer.Builder()
|
||||
@@ -190,6 +229,22 @@ public abstract class ProtocolCustomServer extends EventListener {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to find the issuer certificate of {@code cert} within {@code candidates}.
|
||||
*
|
||||
* @param cert the certificate whose issuer should be found
|
||||
* @param candidates possible issuer certificates
|
||||
* @return issuer certificate if found, otherwise null
|
||||
*/
|
||||
private X509Certificate findIssuer(X509Certificate cert, List<X509Certificate> candidates) {
|
||||
for (X509Certificate ca : candidates) {
|
||||
if (cert.getIssuerX500Principal().equals(ca.getSubjectX500Principal())) {
|
||||
return ca;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the required certificate files exist in the specified folder.
|
||||
*
|
||||
@@ -200,8 +255,6 @@ public abstract class ProtocolCustomServer extends EventListener {
|
||||
* @throws IOException If an I/O error occurs while checking the files.
|
||||
*/
|
||||
private void checkFileExists(File folder, String prefix, String extension) throws CertificateException, IOException {
|
||||
boolean found = false;
|
||||
|
||||
// Ensure the folder exists
|
||||
if (folder == null) throw new FileNotFoundException("Folder does not exist");
|
||||
|
||||
@@ -214,13 +267,7 @@ public abstract class ProtocolCustomServer extends EventListener {
|
||||
for (File file : files) {
|
||||
if (!file.getName().startsWith(prefix))
|
||||
throw new CertificateException(file.getAbsolutePath() + " is not valid");
|
||||
|
||||
// Check for file matching the public IP address
|
||||
if (!found) found = file.getName().equalsIgnoreCase(prefix + NetworkUtils.getPublicIPAddress() + extension);
|
||||
}
|
||||
|
||||
// Throw exception if the required file is not found
|
||||
if (!found) throw new CertificateException("Missing " + prefix + NetworkUtils.getPublicIPAddress() + extension);
|
||||
}
|
||||
|
||||
@Listener(priority = EventPriority.LOW)
|
||||
|
||||
Reference in New Issue
Block a user