Bug fixes

This commit is contained in:
UnlegitDqrk
2026-02-08 22:01:19 +01:00
parent c2e47a8a1e
commit 23a3293060
5 changed files with 98 additions and 49 deletions

View File

@@ -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);
}
}
/**

View File

@@ -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())
);
}
}
}

View File

@@ -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);
}
/**

View File

@@ -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)