mirror of
https://github.com/GravitLauncher/Launcher
synced 2024-12-23 00:51:01 +03:00
[FEATURE] LauncherTrustManager и базовые сертификаты
This commit is contained in:
parent
8a52340b1a
commit
5a2aedbe06
10 changed files with 233 additions and 18 deletions
|
@ -13,6 +13,7 @@
|
||||||
import java.security.InvalidAlgorithmParameterException;
|
import java.security.InvalidAlgorithmParameterException;
|
||||||
import java.security.KeyPair;
|
import java.security.KeyPair;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.cert.CertificateException;
|
||||||
import java.security.interfaces.ECPrivateKey;
|
import java.security.interfaces.ECPrivateKey;
|
||||||
import java.security.interfaces.ECPublicKey;
|
import java.security.interfaces.ECPublicKey;
|
||||||
import java.security.interfaces.RSAPrivateKey;
|
import java.security.interfaces.RSAPrivateKey;
|
||||||
|
@ -274,14 +275,16 @@ public static class LaunchServerDirectories
|
||||||
public Path updatesDir;
|
public Path updatesDir;
|
||||||
public Path profilesDir;
|
public Path profilesDir;
|
||||||
public Path dir;
|
public Path dir;
|
||||||
|
public Path trustStore;
|
||||||
public void collect()
|
public void collect()
|
||||||
{
|
{
|
||||||
if(updatesDir == null) updatesDir = dir.resolve("updates");
|
if(updatesDir == null) updatesDir = dir.resolve("updates");
|
||||||
if(profilesDir == null) profilesDir = dir.resolve("profiles");
|
if(profilesDir == null) profilesDir = dir.resolve("profiles");
|
||||||
|
if(trustStore == null) trustStore = dir.resolve("truststore");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, LaunchServerConfig config, LaunchServerRuntimeConfig runtimeConfig, LaunchServerConfigManager launchServerConfigManager, LaunchServerModulesManager modulesManager, ECPublicKey publicKey, ECPrivateKey privateKey, CommandHandler commandHandler) throws IOException, InvalidKeySpecException {
|
public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, LaunchServerConfig config, LaunchServerRuntimeConfig runtimeConfig, LaunchServerConfigManager launchServerConfigManager, LaunchServerModulesManager modulesManager, ECPublicKey publicKey, ECPrivateKey privateKey, CommandHandler commandHandler, CertificateManager certificateManager) throws IOException {
|
||||||
this.dir = directories.dir;
|
this.dir = directories.dir;
|
||||||
this.env = env;
|
this.env = env;
|
||||||
this.config = config;
|
this.config = config;
|
||||||
|
@ -293,6 +296,7 @@ public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, La
|
||||||
this.privateKey = privateKey;
|
this.privateKey = privateKey;
|
||||||
this.commandHandler = commandHandler;
|
this.commandHandler = commandHandler;
|
||||||
this.runtime = runtimeConfig;
|
this.runtime = runtimeConfig;
|
||||||
|
this.certificateManager = certificateManager;
|
||||||
taskPool = new Timer("Timered task worker thread", true);
|
taskPool = new Timer("Timered task worker thread", true);
|
||||||
launcherLibraries = dir.resolve("launcher-libraries");
|
launcherLibraries = dir.resolve("launcher-libraries");
|
||||||
launcherLibrariesCompile = dir.resolve("launcher-libraries-compile");
|
launcherLibrariesCompile = dir.resolve("launcher-libraries-compile");
|
||||||
|
@ -331,7 +335,6 @@ public LaunchServer(LaunchServerDirectories directories, LaunchServerEnv env, La
|
||||||
reconfigurableManager = new ReconfigurableManager();
|
reconfigurableManager = new ReconfigurableManager();
|
||||||
authHookManager = new AuthHookManager();
|
authHookManager = new AuthHookManager();
|
||||||
configManager = new ConfigManager();
|
configManager = new ConfigManager();
|
||||||
certificateManager = new CertificateManager();
|
|
||||||
//Generate or set new Certificate API
|
//Generate or set new Certificate API
|
||||||
certificateManager.orgName = config.projectName;
|
certificateManager.orgName = config.projectName;
|
||||||
if(config.certificate != null && config.certificate.enabled)
|
if(config.certificate != null && config.certificate.enabled)
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
import pro.gravit.launchserver.config.LaunchServerConfig;
|
import pro.gravit.launchserver.config.LaunchServerConfig;
|
||||||
import pro.gravit.launchserver.config.LaunchServerRuntimeConfig;
|
import pro.gravit.launchserver.config.LaunchServerRuntimeConfig;
|
||||||
|
import pro.gravit.launchserver.manangers.CertificateManager;
|
||||||
import pro.gravit.launchserver.modules.impl.LaunchServerModulesManager;
|
import pro.gravit.launchserver.modules.impl.LaunchServerModulesManager;
|
||||||
import pro.gravit.utils.command.CommandHandler;
|
import pro.gravit.utils.command.CommandHandler;
|
||||||
|
|
||||||
|
@ -20,6 +21,7 @@ public class LaunchServerBuilder {
|
||||||
private LaunchServer.LaunchServerDirectories directories = new LaunchServer.LaunchServerDirectories();
|
private LaunchServer.LaunchServerDirectories directories = new LaunchServer.LaunchServerDirectories();
|
||||||
private ECPublicKey publicKey;
|
private ECPublicKey publicKey;
|
||||||
private ECPrivateKey privateKey;
|
private ECPrivateKey privateKey;
|
||||||
|
private CertificateManager certificateManager;
|
||||||
private LaunchServer.LaunchServerConfigManager launchServerConfigManager;
|
private LaunchServer.LaunchServerConfigManager launchServerConfigManager;
|
||||||
|
|
||||||
public LaunchServerBuilder setConfig(LaunchServerConfig config) {
|
public LaunchServerBuilder setConfig(LaunchServerConfig config) {
|
||||||
|
@ -101,6 +103,11 @@ public void writeRuntimeConfig(LaunchServerRuntimeConfig config) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return new LaunchServer(directories, env, config, runtimeConfig, launchServerConfigManager, modulesManager, publicKey, privateKey, commandHandler);
|
return new LaunchServer(directories, env, config, runtimeConfig, launchServerConfigManager, modulesManager, publicKey, privateKey, commandHandler, certificateManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LaunchServerBuilder setCertificateManager(CertificateManager certificateManager) {
|
||||||
|
this.certificateManager = certificateManager;
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
import java.security.KeyPair;
|
import java.security.KeyPair;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
import java.security.Security;
|
import java.security.Security;
|
||||||
|
import java.security.cert.CertificateException;
|
||||||
import java.security.interfaces.ECPrivateKey;
|
import java.security.interfaces.ECPrivateKey;
|
||||||
import java.security.interfaces.ECPublicKey;
|
import java.security.interfaces.ECPublicKey;
|
||||||
|
|
||||||
|
@ -27,6 +28,7 @@
|
||||||
import pro.gravit.launchserver.config.LaunchServerConfig;
|
import pro.gravit.launchserver.config.LaunchServerConfig;
|
||||||
import pro.gravit.launchserver.config.LaunchServerRuntimeConfig;
|
import pro.gravit.launchserver.config.LaunchServerRuntimeConfig;
|
||||||
import pro.gravit.launchserver.dao.provider.DaoProvider;
|
import pro.gravit.launchserver.dao.provider.DaoProvider;
|
||||||
|
import pro.gravit.launchserver.manangers.CertificateManager;
|
||||||
import pro.gravit.launchserver.manangers.LaunchServerGsonManager;
|
import pro.gravit.launchserver.manangers.LaunchServerGsonManager;
|
||||||
import pro.gravit.launchserver.modules.impl.LaunchServerModulesManager;
|
import pro.gravit.launchserver.modules.impl.LaunchServerModulesManager;
|
||||||
import pro.gravit.launchserver.socket.WebSocketService;
|
import pro.gravit.launchserver.socket.WebSocketService;
|
||||||
|
@ -37,12 +39,12 @@
|
||||||
import pro.gravit.utils.helper.JVMHelper;
|
import pro.gravit.utils.helper.JVMHelper;
|
||||||
import pro.gravit.utils.helper.LogHelper;
|
import pro.gravit.utils.helper.LogHelper;
|
||||||
import pro.gravit.utils.helper.SecurityHelper;
|
import pro.gravit.utils.helper.SecurityHelper;
|
||||||
|
import pro.gravit.utils.verify.LauncherTrustManager;
|
||||||
|
|
||||||
import javax.crypto.Cipher;
|
import javax.crypto.Cipher;
|
||||||
|
|
||||||
public class LaunchServerStarter {
|
public class LaunchServerStarter {
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
Security.addProvider(new BouncyCastleProvider());
|
|
||||||
JVMHelper.checkStackTrace(LaunchServerStarter.class);
|
JVMHelper.checkStackTrace(LaunchServerStarter.class);
|
||||||
JVMHelper.verifySystemProperties(LaunchServer.class, true);
|
JVMHelper.verifySystemProperties(LaunchServer.class, true);
|
||||||
LogHelper.addOutput(IOHelper.WORKING_DIR.resolve("LaunchServer.log"));
|
LogHelper.addOutput(IOHelper.WORKING_DIR.resolve("LaunchServer.log"));
|
||||||
|
@ -52,18 +54,24 @@ public static void main(String[] args) throws Exception {
|
||||||
LogHelper.error("StarterAgent is not started!");
|
LogHelper.error("StarterAgent is not started!");
|
||||||
LogHelper.error("You should add to JVM options this option: `-javaagent:LaunchServer.jar`");
|
LogHelper.error("You should add to JVM options this option: `-javaagent:LaunchServer.jar`");
|
||||||
}
|
}
|
||||||
|
|
||||||
Path dir = IOHelper.WORKING_DIR;
|
Path dir = IOHelper.WORKING_DIR;
|
||||||
Path configFile, runtimeConfigFile;
|
Path configFile, runtimeConfigFile;
|
||||||
Path publicKeyFile =dir.resolve("public.key");
|
Path publicKeyFile =dir.resolve("public.key");
|
||||||
Path privateKeyFile = dir.resolve("private.key");
|
Path privateKeyFile = dir.resolve("private.key");
|
||||||
ECPublicKey publicKey;
|
ECPublicKey publicKey;
|
||||||
ECPrivateKey privateKey;
|
ECPrivateKey privateKey;
|
||||||
|
Security.addProvider(new BouncyCastleProvider());
|
||||||
|
CertificateManager certificateManager = new CertificateManager();
|
||||||
|
try {
|
||||||
|
certificateManager.readTrustStore(dir.resolve("truststore"));
|
||||||
|
} catch (CertificateException e) {
|
||||||
|
throw new IOException(e);
|
||||||
|
}
|
||||||
|
|
||||||
LaunchServerRuntimeConfig runtimeConfig;
|
LaunchServerRuntimeConfig runtimeConfig;
|
||||||
LaunchServerConfig config;
|
LaunchServerConfig config;
|
||||||
LaunchServer.LaunchServerEnv env = LaunchServer.LaunchServerEnv.PRODUCTION;
|
LaunchServer.LaunchServerEnv env = LaunchServer.LaunchServerEnv.PRODUCTION;
|
||||||
LaunchServerModulesManager modulesManager = new LaunchServerModulesManager(dir.resolve("modules"), dir.resolve("config"));
|
LaunchServerModulesManager modulesManager = new LaunchServerModulesManager(dir.resolve("modules"), dir.resolve("config"), certificateManager.trustManager);
|
||||||
modulesManager.autoload();
|
modulesManager.autoload();
|
||||||
modulesManager.initModules(null);
|
modulesManager.initModules(null);
|
||||||
registerAll();
|
registerAll();
|
||||||
|
@ -173,6 +181,7 @@ public void writeRuntimeConfig(LaunchServerRuntimeConfig config) throws IOExcept
|
||||||
.setConfig(config)
|
.setConfig(config)
|
||||||
.setModulesManager(modulesManager)
|
.setModulesManager(modulesManager)
|
||||||
.setLaunchServerConfigManager(launchServerConfigManager)
|
.setLaunchServerConfigManager(launchServerConfigManager)
|
||||||
|
.setCertificateManager(certificateManager)
|
||||||
.build();
|
.build();
|
||||||
server.run();
|
server.run();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,25 +1,31 @@
|
||||||
package pro.gravit.launchserver.manangers;
|
package pro.gravit.launchserver.manangers;
|
||||||
|
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.*;
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.Reader;
|
|
||||||
import java.io.Writer;
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
|
import java.nio.file.FileVisitResult;
|
||||||
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.SimpleFileVisitor;
|
||||||
|
import java.nio.file.attribute.BasicFileAttributes;
|
||||||
import java.security.InvalidAlgorithmParameterException;
|
import java.security.InvalidAlgorithmParameterException;
|
||||||
import java.security.KeyPair;
|
import java.security.KeyPair;
|
||||||
import java.security.KeyPairGenerator;
|
import java.security.KeyPairGenerator;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.PrivateKey;
|
import java.security.PrivateKey;
|
||||||
import java.security.PublicKey;
|
import java.security.PublicKey;
|
||||||
|
import java.security.cert.CertificateException;
|
||||||
|
import java.security.cert.CertificateFactory;
|
||||||
|
import java.security.cert.X509Certificate;
|
||||||
import java.security.spec.ECGenParameterSpec;
|
import java.security.spec.ECGenParameterSpec;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
import java.time.temporal.ChronoUnit;
|
import java.time.temporal.ChronoUnit;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
|
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
|
||||||
import org.bouncycastle.asn1.x500.X500Name;
|
import org.bouncycastle.asn1.x500.X500Name;
|
||||||
|
@ -43,6 +49,7 @@
|
||||||
|
|
||||||
import pro.gravit.utils.helper.IOHelper;
|
import pro.gravit.utils.helper.IOHelper;
|
||||||
import pro.gravit.utils.helper.SecurityHelper;
|
import pro.gravit.utils.helper.SecurityHelper;
|
||||||
|
import pro.gravit.utils.verify.LauncherTrustManager;
|
||||||
|
|
||||||
public class CertificateManager {
|
public class CertificateManager {
|
||||||
public X509CertificateHolder ca;
|
public X509CertificateHolder ca;
|
||||||
|
@ -51,9 +58,7 @@ public class CertificateManager {
|
||||||
public X509CertificateHolder server;
|
public X509CertificateHolder server;
|
||||||
public AsymmetricKeyParameter serverKey;
|
public AsymmetricKeyParameter serverKey;
|
||||||
|
|
||||||
|
public LauncherTrustManager trustManager;
|
||||||
//public X509CertificateHolder server;
|
|
||||||
//public AsymmetricKeyParameter serverKey;
|
|
||||||
|
|
||||||
public int validDays = 60;
|
public int validDays = 60;
|
||||||
public int minusHours = 6;
|
public int minusHours = 6;
|
||||||
|
@ -172,4 +177,34 @@ public X509CertificateHolder readCertificate(Reader reader) throws IOException {
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void readTrustStore(Path dir) throws IOException, CertificateException {
|
||||||
|
if(!IOHelper.isDir(dir))
|
||||||
|
{
|
||||||
|
Files.createDirectories(dir);
|
||||||
|
try(OutputStream outputStream = IOHelper.newOutput(dir.resolve("GravitCentralRootCA.crt"));
|
||||||
|
InputStream inputStream = IOHelper.newInput(IOHelper.getResourceURL("pro/gravit/launchserver/defaults/GravitCentralRootCA.crt")))
|
||||||
|
{
|
||||||
|
IOHelper.transfer(inputStream, outputStream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
List<X509Certificate> certificates = new ArrayList<>();
|
||||||
|
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
|
||||||
|
IOHelper.walk(dir, new SimpleFileVisitor<Path>() {
|
||||||
|
@Override
|
||||||
|
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
||||||
|
if(file.toFile().getName().endsWith(".crt"))
|
||||||
|
{
|
||||||
|
try(InputStream inputStream = IOHelper.newInput(file))
|
||||||
|
{
|
||||||
|
certificates.add((X509Certificate) certFactory.generateCertificate(inputStream));
|
||||||
|
} catch (CertificateException e) {
|
||||||
|
throw new IOException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.visitFile(file, attrs);
|
||||||
|
}
|
||||||
|
}, false);
|
||||||
|
trustManager = new LauncherTrustManager(certificates.toArray(new X509Certificate[0]));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,12 +7,14 @@
|
||||||
import pro.gravit.launcher.modules.LauncherModuleInfo;
|
import pro.gravit.launcher.modules.LauncherModuleInfo;
|
||||||
import pro.gravit.launcher.modules.impl.SimpleModuleManager;
|
import pro.gravit.launcher.modules.impl.SimpleModuleManager;
|
||||||
import pro.gravit.launchserver.LaunchServer;
|
import pro.gravit.launchserver.LaunchServer;
|
||||||
|
import pro.gravit.launchserver.manangers.CertificateManager;
|
||||||
import pro.gravit.utils.helper.LogHelper;
|
import pro.gravit.utils.helper.LogHelper;
|
||||||
|
import pro.gravit.utils.verify.LauncherTrustManager;
|
||||||
|
|
||||||
public class LaunchServerModulesManager extends SimpleModuleManager {
|
public class LaunchServerModulesManager extends SimpleModuleManager {
|
||||||
public LaunchServerCoreModule coreModule;
|
public LaunchServerCoreModule coreModule;
|
||||||
public LaunchServerModulesManager(Path modulesDir, Path configDir) {
|
public LaunchServerModulesManager(Path modulesDir, Path configDir, LauncherTrustManager trustManager) {
|
||||||
super(modulesDir, configDir);
|
super(modulesDir, configDir, trustManager);
|
||||||
coreModule = new LaunchServerCoreModule();
|
coreModule = new LaunchServerCoreModule();
|
||||||
modules.add(coreModule);
|
modules.add(coreModule);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIFyjCCA7KgAwIBAgIRALnsjNjfvOTXfla3fX1fNEUwDQYJKoZIhvcNAQELBQAw
|
||||||
|
WTELMAkGA1UEBhMCUlUxFzAVBgNVBAoTDkdyYXZpdFRydXN0IENBMRAwDgYDVQQL
|
||||||
|
EwdSb290IENBMR8wHQYDVQQDExZHcmF2aXQgQ2VudHJhbCBSb290IENBMCAXDTE5
|
||||||
|
MDYwOTAyNDIwMFoYDzIwNTEwNjA5MDI0MjAwWjBZMQswCQYDVQQGEwJSVTEXMBUG
|
||||||
|
A1UEChMOR3Jhdml0VHJ1c3QgQ0ExEDAOBgNVBAsTB1Jvb3QgQ0ExHzAdBgNVBAMT
|
||||||
|
FkdyYXZpdCBDZW50cmFsIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw
|
||||||
|
ggIKAoICAQDA3Qm9OH8Xz3YM3bKkZuQI7T/aL3ulMOdY5GFADYgHrOVZXVSJi/4P
|
||||||
|
PruBsut4WXN6TGQdpJtNZ2kyWTYzENGTm/TMzBcIchor1M3JW5Uv/C0r5gSEU1uP
|
||||||
|
DPe7oEpeKtb3FXML/pGoGpLv/sonTKky4AKZnK7B15bZ+oVZNwh7UKANpNrVA8k5
|
||||||
|
0gb4BisFcegLidYL9Y00H1x5WzUxldQAA1IQuwdkL3NP0NPQrSVJ2Ka2EtebE2HP
|
||||||
|
fXHtbftvvnvSWyh4CXAxTfEmJgut0gSPQPm9wVt6pIWWd4O0hHwVmxkKQidgnP6A
|
||||||
|
+d05FnJGsBw0ztMCifIteqNiHF0D8E0GuSz6NtcuV47J3p43qkvKr2vPc8o6WMN8
|
||||||
|
PAb0eVHc/AX8qqOwYQyHlj4M0SDhCltHeeYRWmuZmRFIIelv6VAocaQLlPQrhJNp
|
||||||
|
feIzmXLy60a+84vpe/eQKQx+D8a1elarQkoHMxI7x/9AJvxcnJ4KuXc2rkiu3Zv9
|
||||||
|
KMhixtkLc+pA6jY023U211v+c20RjTqwKIZoMFc7BZipoinAOn1bdsTzXlhOMv1O
|
||||||
|
zj5WoW6DsQQONMZNyLQAkaX6SYZE/kQVJ9YMPhNdaXjxxzfrY05IrWAaWhtPbW8z
|
||||||
|
5nb4/JyO+bJq3v2rav9p03s8P/lQ4k/0af5vOkGkEO0+YKx97ZP8FQIDAQABo4GK
|
||||||
|
MIGHMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFjMGCvHXAE/vGJih+Lfdo2s
|
||||||
|
YnzsMAsGA1UdDwQEAwIBBjA1BgNVHR8ELjAsMCqgKKAmhiRodHRwOi8vY2EuZ3Jh
|
||||||
|
dml0LnByby9jZW50cmFscm9vdC5jcmwwEQYJYIZIAYb4QgEBBAQDAgAHMA0GCSqG
|
||||||
|
SIb3DQEBCwUAA4ICAQAexCGpThx85skEllva1UskmdlRh3rud9u59AUiwNZF0b0I
|
||||||
|
+7eeyLNaLHarg2Zm30TSCF53ksyPTE5QNdmozs1fl3MddFqunkbUm4G6hwedZMSi
|
||||||
|
4IXIb2QK3z3gZG5ZNdHaDG2u00Jdkc39h3jQFp1rpn4+0DcnYJAe+lw5G+XHURY2
|
||||||
|
j15wcmUFp/Ywgw3pfCWmH5+rxq21e/LG8JiQrxekkFI2GUD+Qw7+Hq3o1Fgg3kfh
|
||||||
|
Lg4B5WEbEICQ1FC+dHYHasEI3q3c96Qpqu2k3pO0l1fr6Cys+AGjoI2WrgXkGlmA
|
||||||
|
F+Wi2ndoZbvspGAwxmrNMtLE3OYNuMXFF410QSPf4o9QqpGDC3a2mccTXb231a18
|
||||||
|
5vDJixeZpuzEm5ECXg8j6aj53X3rtm7C8yfOsg5UTKJJj+pSNz4YTp91IDHm0nTP
|
||||||
|
2KhrgS7jujgKdJn9xv07e/API3kLWkVmMwHBiaSCIaHOfAN0RJMQVV+YgnSp2sIa
|
||||||
|
OATWgSKH0qTkleE/v7k+USs0a+KV8wmC5wwliqH+uLO++yIP/9bjDctyLulQX5Ee
|
||||||
|
+EhD7tb1R/yyWY4uhkzlsr3N2Kl34aQAEBMn8Z1mHsyyu1FcbEaNLU8jcS3pHPVM
|
||||||
|
gQRn3m1iDnQlFciAMxW0pW6mW/4xKYzhXk5BTSolnqMVylxHgWXuBwdDDQQVnQ==
|
||||||
|
-----END CERTIFICATE-----
|
|
@ -16,6 +16,7 @@
|
||||||
import pro.gravit.launcher.Launcher;
|
import pro.gravit.launcher.Launcher;
|
||||||
import pro.gravit.launchserver.config.LaunchServerConfig;
|
import pro.gravit.launchserver.config.LaunchServerConfig;
|
||||||
import pro.gravit.launchserver.config.LaunchServerRuntimeConfig;
|
import pro.gravit.launchserver.config.LaunchServerRuntimeConfig;
|
||||||
|
import pro.gravit.launchserver.manangers.CertificateManager;
|
||||||
import pro.gravit.launchserver.manangers.LaunchServerGsonManager;
|
import pro.gravit.launchserver.manangers.LaunchServerGsonManager;
|
||||||
import pro.gravit.launchserver.modules.impl.LaunchServerModulesManager;
|
import pro.gravit.launchserver.modules.impl.LaunchServerModulesManager;
|
||||||
import pro.gravit.utils.command.StdCommandHandler;
|
import pro.gravit.utils.command.StdCommandHandler;
|
||||||
|
@ -32,7 +33,7 @@ public class StartLaunchServerTest {
|
||||||
@BeforeAll
|
@BeforeAll
|
||||||
public static void prepare() throws Exception
|
public static void prepare() throws Exception
|
||||||
{
|
{
|
||||||
LaunchServerModulesManager modulesManager = new LaunchServerModulesManager(modulesDir, configDir);
|
LaunchServerModulesManager modulesManager = new LaunchServerModulesManager(modulesDir, configDir, null);
|
||||||
LaunchServerConfig config = LaunchServerConfig.getDefault(LaunchServer.LaunchServerEnv.TEST);
|
LaunchServerConfig config = LaunchServerConfig.getDefault(LaunchServer.LaunchServerEnv.TEST);
|
||||||
Launcher.gsonManager = new LaunchServerGsonManager(modulesManager);
|
Launcher.gsonManager = new LaunchServerGsonManager(modulesManager);
|
||||||
Launcher.gsonManager.initGson();
|
Launcher.gsonManager.initGson();
|
||||||
|
@ -47,6 +48,7 @@ public static void prepare() throws Exception
|
||||||
.setRuntimeConfig(runtimeConfig)
|
.setRuntimeConfig(runtimeConfig)
|
||||||
.setPublicKey(publicKey)
|
.setPublicKey(publicKey)
|
||||||
.setPrivateKey(privateKey)
|
.setPrivateKey(privateKey)
|
||||||
|
.setCertificateManager(new CertificateManager())
|
||||||
.setLaunchServerConfigManager(new LaunchServer.LaunchServerConfigManager() {
|
.setLaunchServerConfigManager(new LaunchServer.LaunchServerConfigManager() {
|
||||||
@Override
|
@Override
|
||||||
public LaunchServerConfig readConfig() throws IOException {
|
public LaunchServerConfig readConfig() throws IOException {
|
||||||
|
|
|
@ -7,6 +7,12 @@
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.SimpleFileVisitor;
|
import java.nio.file.SimpleFileVisitor;
|
||||||
import java.nio.file.attribute.BasicFileAttributes;
|
import java.nio.file.attribute.BasicFileAttributes;
|
||||||
|
import java.security.InvalidKeyException;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.NoSuchProviderException;
|
||||||
|
import java.security.SignatureException;
|
||||||
|
import java.security.cert.CertificateException;
|
||||||
|
import java.security.cert.X509Certificate;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -22,7 +28,9 @@
|
||||||
import pro.gravit.utils.PublicURLClassLoader;
|
import pro.gravit.utils.PublicURLClassLoader;
|
||||||
import pro.gravit.utils.Version;
|
import pro.gravit.utils.Version;
|
||||||
import pro.gravit.utils.helper.IOHelper;
|
import pro.gravit.utils.helper.IOHelper;
|
||||||
|
import pro.gravit.utils.helper.JVMHelper;
|
||||||
import pro.gravit.utils.helper.LogHelper;
|
import pro.gravit.utils.helper.LogHelper;
|
||||||
|
import pro.gravit.utils.verify.LauncherTrustManager;
|
||||||
|
|
||||||
public class SimpleModuleManager implements LauncherModulesManager {
|
public class SimpleModuleManager implements LauncherModulesManager {
|
||||||
protected final List<LauncherModule> modules = new ArrayList<>();
|
protected final List<LauncherModule> modules = new ArrayList<>();
|
||||||
|
@ -30,6 +38,7 @@ public class SimpleModuleManager implements LauncherModulesManager {
|
||||||
protected final SimpleModuleContext context;
|
protected final SimpleModuleContext context;
|
||||||
protected final ModulesConfigManager modulesConfigManager;
|
protected final ModulesConfigManager modulesConfigManager;
|
||||||
protected final Path modulesDir;
|
protected final Path modulesDir;
|
||||||
|
protected final LauncherTrustManager trustManager;
|
||||||
protected LauncherInitContext initContext;
|
protected LauncherInitContext initContext;
|
||||||
|
|
||||||
protected PublicURLClassLoader classLoader = new PublicURLClassLoader(new URL[]{});
|
protected PublicURLClassLoader classLoader = new PublicURLClassLoader(new URL[]{});
|
||||||
|
@ -113,6 +122,13 @@ public SimpleModuleManager(Path modulesDir, Path configDir) {
|
||||||
modulesConfigManager = new SimpleModulesConfigManager(configDir);
|
modulesConfigManager = new SimpleModulesConfigManager(configDir);
|
||||||
context = new SimpleModuleContext(this, modulesConfigManager);
|
context = new SimpleModuleContext(this, modulesConfigManager);
|
||||||
this.modulesDir = modulesDir;
|
this.modulesDir = modulesDir;
|
||||||
|
this.trustManager = null;
|
||||||
|
}
|
||||||
|
public SimpleModuleManager(Path modulesDir, Path configDir, LauncherTrustManager trustManager) {
|
||||||
|
modulesConfigManager = new SimpleModulesConfigManager(configDir);
|
||||||
|
context = new SimpleModuleContext(this, modulesConfigManager);
|
||||||
|
this.modulesDir = modulesDir;
|
||||||
|
this.trustManager = trustManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -142,7 +158,10 @@ public LauncherModule loadModule(Path file) throws IOException {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
classLoader.addURL(file.toUri().toURL());
|
classLoader.addURL(file.toUri().toURL());
|
||||||
LauncherModule module = (LauncherModule) Class.forName(moduleClass, true, classLoader).newInstance();
|
@SuppressWarnings("unchecked cast")
|
||||||
|
Class<? extends LauncherModule> clazz = (Class<? extends LauncherModule>) Class.forName(moduleClass, false, classLoader);
|
||||||
|
checkModuleClass(clazz);
|
||||||
|
LauncherModule module = clazz.newInstance();
|
||||||
loadModule(module);
|
loadModule(module);
|
||||||
return module;
|
return module;
|
||||||
} catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
|
} catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
|
||||||
|
@ -152,6 +171,23 @@ public LauncherModule loadModule(Path file) throws IOException {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void checkModuleClass(Class<? extends LauncherModule> clazz) throws SecurityException
|
||||||
|
{
|
||||||
|
if(trustManager == null) return;
|
||||||
|
X509Certificate[] certificates = JVMHelper.getCertificates(clazz);
|
||||||
|
if(certificates == null)
|
||||||
|
{
|
||||||
|
LogHelper.warning("Module class %s not signed", clazz.getName());
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
trustManager.checkCertificate(certificates, (c,s) -> {
|
||||||
|
|
||||||
|
});
|
||||||
|
} catch (CertificateException | NoSuchProviderException | NoSuchAlgorithmException | InvalidKeyException | SignatureException e) {
|
||||||
|
throw new SecurityException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LauncherModule getModule(String name) {
|
public LauncherModule getModule(String name) {
|
||||||
for(LauncherModule module : modules)
|
for(LauncherModule module : modules)
|
||||||
|
|
|
@ -114,7 +114,7 @@ public static URL[] getClassPathURL() {
|
||||||
public static X509Certificate[] getCertificates(Class<?> clazz)
|
public static X509Certificate[] getCertificates(Class<?> clazz)
|
||||||
{
|
{
|
||||||
Object[] signers = clazz.getSigners();
|
Object[] signers = clazz.getSigners();
|
||||||
if(signers == null) return new X509Certificate[] {};
|
if(signers == null) return null;
|
||||||
return Arrays.stream(signers).filter((c) -> c instanceof X509Certificate).map((c) -> (X509Certificate) c).toArray(X509Certificate[]::new);
|
return Arrays.stream(signers).filter((c) -> c instanceof X509Certificate).map((c) -> (X509Certificate) c).toArray(X509Certificate[]::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
package pro.gravit.utils.verify;
|
||||||
|
|
||||||
|
import pro.gravit.utils.helper.LogHelper;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.security.InvalidKeyException;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.NoSuchProviderException;
|
||||||
|
import java.security.SignatureException;
|
||||||
|
import java.security.cert.CertificateEncodingException;
|
||||||
|
import java.security.cert.CertificateException;
|
||||||
|
import java.security.cert.CertificateFactory;
|
||||||
|
import java.security.cert.X509Certificate;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class LauncherTrustManager {
|
||||||
|
private final X509Certificate[] trustSigners;
|
||||||
|
private final List<X509Certificate> trustCache = new ArrayList<>();
|
||||||
|
|
||||||
|
public LauncherTrustManager(X509Certificate[] trustSigners) {
|
||||||
|
this.trustSigners = trustSigners;
|
||||||
|
}
|
||||||
|
public LauncherTrustManager(byte[][] encodedCertificate) throws CertificateException {
|
||||||
|
CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
|
||||||
|
trustSigners = Arrays.stream(encodedCertificate).map((cert) -> {
|
||||||
|
try(InputStream input = new ByteArrayInputStream(cert))
|
||||||
|
{
|
||||||
|
return (X509Certificate) certFactory.generateCertificate(input);
|
||||||
|
} catch (IOException | CertificateException e) {
|
||||||
|
LogHelper.error(e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}).toArray(X509Certificate[]::new);
|
||||||
|
}
|
||||||
|
public interface CertificateChecker
|
||||||
|
{
|
||||||
|
void check(X509Certificate cert, X509Certificate signer) throws CertificateException, SecurityException;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkCertificate(X509Certificate[] certs, CertificateChecker checker) throws CertificateException, NoSuchProviderException, NoSuchAlgorithmException, InvalidKeyException, SignatureException {
|
||||||
|
if(certs == null) throw new SecurityException("Object not signed");
|
||||||
|
for(int i=0;i< certs.length;++i)
|
||||||
|
{
|
||||||
|
X509Certificate cert = certs[i];
|
||||||
|
if(trustCache.contains(cert))
|
||||||
|
{
|
||||||
|
//Добавляем в кеш все проверенные сертификаты
|
||||||
|
for(int j=0;j < i;++j)
|
||||||
|
trustCache.add(certs[j]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
X509Certificate signer = (i+1 < certs.length) ? certs[i+1] : null;
|
||||||
|
cert.checkValidity();
|
||||||
|
if(signer != null)
|
||||||
|
{
|
||||||
|
cert.verify(signer.getPublicKey());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(!isTrusted(cert))
|
||||||
|
{
|
||||||
|
throw new CertificateException(String.format("Certificate %s is not signed by a trusted signer", cert.getSubjectDN().getName()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
checker.check(cert, signer);
|
||||||
|
}
|
||||||
|
Collections.addAll(trustCache, certs);
|
||||||
|
}
|
||||||
|
public boolean isTrusted(X509Certificate certificate) throws CertificateEncodingException {
|
||||||
|
//Java API не дает возможности вызвать getFingerprint
|
||||||
|
//Oracle использует хак с кастом к sun.security.x509.X509CertImpl для проверки равенства сертификатов
|
||||||
|
//Мы пойдем более медленным путем
|
||||||
|
for(X509Certificate cert : trustSigners)
|
||||||
|
{
|
||||||
|
if(cert.getSerialNumber().equals(certificate.getSerialNumber()) //Проверка serialNumber (быстро)
|
||||||
|
&& Arrays.equals(cert.getEncoded(), certificate.getEncoded())) //Полная проверка (медленно)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue