diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/JARLauncherBinary.java b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/JARLauncherBinary.java index 23547d02..79211cff 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/JARLauncherBinary.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/JARLauncherBinary.java @@ -41,6 +41,7 @@ public JARLauncherBinary(LaunchServer server) throws IOException { @Override public void init() { tasks.add(new PrepareBuildTask(server)); + if(!server.config.sign.enabled) tasks.add(new CertificateAutogenTask(server)); tasks.add(new MainBuildTask(server)); if (server.config.launcher.attachLibraryBeforeProGuard) tasks.add(new AttachJarsTask(server)); tasks.add(new ProGuardBuildTask(server)); diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/CertificateAutogenTask.java b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/CertificateAutogenTask.java new file mode 100644 index 00000000..c597034f --- /dev/null +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/CertificateAutogenTask.java @@ -0,0 +1,80 @@ +package pro.gravit.launchserver.binary.tasks; + +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.asn1.x500.X500NameBuilder; +import org.bouncycastle.asn1.x500.style.BCStyle; +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import org.bouncycastle.cert.X509CertificateHolder; +import org.bouncycastle.cert.X509v3CertificateBuilder; +import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; +import org.bouncycastle.cms.CMSException; +import org.bouncycastle.cms.CMSSignedDataGenerator; +import org.bouncycastle.operator.ContentSigner; +import org.bouncycastle.operator.OperatorCreationException; +import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; +import pro.gravit.launchserver.LaunchServer; +import pro.gravit.launchserver.helper.SignHelper; +import pro.gravit.utils.helper.LogHelper; + +import java.io.IOException; +import java.math.BigInteger; +import java.nio.file.Path; +import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.Date; + +public class CertificateAutogenTask implements LauncherBuildTask { + private LaunchServer server; + + public CertificateAutogenTask(LaunchServer server) { + this.server = server; + } + + @Override + public String getName() { + return "CertificateAutogen"; + } + public X509Certificate certificate; + public X509CertificateHolder bcCertificate; + public CMSSignedDataGenerator signedDataGenerator; + + @Override + public Path process(Path inputFile) throws IOException { + if(signedDataGenerator != null) return inputFile; + try { + X500NameBuilder subject = new X500NameBuilder(); + subject.addRDN(BCStyle.CN, server.config.projectName.concat(" Autogenerated")); + subject.addRDN(BCStyle.O, server.config.projectName); + LocalDateTime startDate = LocalDate.now().atStartOfDay(); + X509v3CertificateBuilder builder = new X509v3CertificateBuilder( + subject.build(), + new BigInteger("0"), + Date.from(startDate.atZone(ZoneId.systemDefault()).toInstant()), + Date.from(startDate.plusDays(3650).atZone(ZoneId.systemDefault()).toInstant()), + new X500Name("CN=ca"), + SubjectPublicKeyInfo.getInstance(server.publicKey.getEncoded())); + JcaContentSignerBuilder csBuilder = new JcaContentSignerBuilder("SHA256WITHECDSA"); + ContentSigner signer = csBuilder.build(server.privateKey); + bcCertificate = builder.build(signer); + certificate = new JcaX509CertificateConverter().setProvider( "BC" ) + .getCertificate( bcCertificate ); + ArrayList chain = new ArrayList<>(); + chain.add(certificate); + signedDataGenerator = SignHelper.createSignedDataGenerator(server.privateKey, certificate, chain, "SHA256WITHECDSA"); + } catch (OperatorCreationException | CMSException | CertificateException e) { + LogHelper.error(e); + } + return inputFile; + } + + @Override + public boolean allowDelete() { + return false; + } +} diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/MainBuildTask.java b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/MainBuildTask.java index 5742cdfb..c483fae6 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/MainBuildTask.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/MainBuildTask.java @@ -23,10 +23,8 @@ import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; import java.security.cert.CertificateEncodingException; -import java.util.Arrays; -import java.util.Base64; -import java.util.HashMap; -import java.util.Map; +import java.security.cert.X509Certificate; +import java.util.*; import java.util.jar.JarFile; import java.util.stream.Collectors; import java.util.zip.ZipEntry; @@ -138,14 +136,24 @@ public Path process(Path inputJar) throws IOException { launcherConfigurator.setBooleanField("isWarningMissArchJava", server.config.launcher.warningMissArchJava); launcherConfigurator.setEnv(server.config.env); launcherConfigurator.setStringField("passwordEncryptKey", server.runtime.passwordEncryptKey); - secureConfigurator.setByteArrayListField("certificates", Arrays.stream(server.certificateManager.trustManager.getTrusted()).map(e -> { - try { - return e.getEncoded(); - } catch (CertificateEncodingException e2) { - LogHelper.error(e2); - return new byte[0]; - } - }).collect(Collectors.toList())); + List certificates = Arrays.stream(server.certificateManager.trustManager.getTrusted()).map(e -> { + try { + return e.getEncoded(); + } catch (CertificateEncodingException e2) { + LogHelper.error(e2); + return new byte[0]; + } + }).collect(Collectors.toList()); + if(!server.config.sign.enabled) + { + CertificateAutogenTask task = TaskUtil.getTaskByClass(server.launcherBinary.tasks, CertificateAutogenTask.class).get(0); + try { + certificates.add(task.certificate.getEncoded()); + } catch (CertificateEncodingException e) { + throw new InternalError(e); + } + } + secureConfigurator.setByteArrayListField("certificates", certificates); String launcherSalt = SecurityHelper.randomStringToken(); byte[] launcherSecureHash = SecurityHelper.digest(SecurityHelper.DigestAlgorithm.SHA256, server.runtime.clientCheckSecret.concat(".").concat(launcherSalt)); diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/SignJarTask.java b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/SignJarTask.java index 4711dcc2..32e42e66 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/SignJarTask.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/tasks/SignJarTask.java @@ -91,11 +91,8 @@ private void stdSign(LaunchServerConfig.JarSignerConf config, Path inputFile, Pa } private void autoSign(Path inputFile, Path signedFile) throws IOException { try (SignerJar output = new SignerJar(new ZipOutputStream(IOHelper.newOutput(signedFile)), () -> { - try { - return genCertificate(srv.config.projectName, srv.publicKey, srv.privateKey); - } catch (OperatorCreationException | CertificateException | CMSException e) { - throw new InternalError(e); - } + CertificateAutogenTask task = TaskUtil.getTaskByClass(srv.launcherBinary.tasks, CertificateAutogenTask.class).get(0); + return task.signedDataGenerator; }, "AUTOGEN.SF", "AUTOGEN.EC"); ZipInputStream input = new ZipInputStream(IOHelper.newInput(inputFile))) { @@ -129,26 +126,4 @@ public static CMSSignedDataGenerator gen(LaunchServerConfig.JarSignerConf config return null; } } - public static CMSSignedDataGenerator genCertificate(String projectName, ECPublicKey publicKey, ECPrivateKey privateKey) throws OperatorCreationException, CertificateException, CMSException { - - X500NameBuilder subject = new X500NameBuilder(); - subject.addRDN(BCStyle.CN, projectName.concat(" Autogenerated")); - subject.addRDN(BCStyle.O, projectName); - LocalDateTime startDate = LocalDate.now().atStartOfDay(); - X509v3CertificateBuilder builder = new X509v3CertificateBuilder( - subject.build(), - new BigInteger("0"), - Date.from(startDate.atZone(ZoneId.systemDefault()).toInstant()), - Date.from(startDate.plusDays(3650).atZone(ZoneId.systemDefault()).toInstant()), - new X500Name("CN=ca"), - SubjectPublicKeyInfo.getInstance(publicKey.getEncoded())); - JcaContentSignerBuilder csBuilder = new JcaContentSignerBuilder("SHA256WITHECDSA"); - ContentSigner signer = csBuilder.build(privateKey); - X509CertificateHolder certificate = builder.build(signer); - X509Certificate x509Certificate = new JcaX509CertificateConverter().setProvider( "BC" ) - .getCertificate( certificate ); - ArrayList chain = new ArrayList<>(); - chain.add(x509Certificate); - return SignHelper.createSignedDataGenerator(privateKey, x509Certificate, chain, "SHA256WITHECDSA"); - } }