From 625fb75f825ee3880a522ae864c5a83aa6b68d0f Mon Sep 17 00:00:00 2001 From: Gravit Date: Sun, 27 Oct 2019 21:47:55 +0700 Subject: [PATCH] =?UTF-8?q?[FEATURE]=20=D0=90=D0=B2=D1=82=D0=BE=D0=B3?= =?UTF-8?q?=D0=B5=D0=BD=D0=B5=D1=80=D0=B0=D1=86=D0=B8=D1=8F=20=D1=81=D0=B5?= =?UTF-8?q?=D1=80=D1=82=D0=B8=D1=84=D0=B8=D0=BA=D0=B0=D1=82=D0=B0=20=D0=BD?= =?UTF-8?q?=D0=B0=20=D0=BB=D0=B5=D1=82=D1=83=20=D0=BF=D1=80=D0=B8=20=D0=B5?= =?UTF-8?q?=D0=B3=D0=BE=20=D0=BE=D1=82=D1=81=D1=83=D1=82=D1=81=D1=82=D0=B2?= =?UTF-8?q?=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../binary/JARLauncherBinary.java | 2 +- .../binary/tasks/SignJarTask.java | 73 ++++++++++++++++++- .../command/service/SignDirCommand.java | 11 ++- .../command/service/SignJarCommand.java | 4 +- .../config/LaunchServerConfig.java | 2 +- .../launchserver/helper/SignHelper.java | 11 +++ .../manangers/CertificateManager.java | 4 +- 7 files changed, 99 insertions(+), 8 deletions(-) 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 b8082682..23547d02 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/binary/JARLauncherBinary.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/binary/JARLauncherBinary.java @@ -47,7 +47,7 @@ public void init() { tasks.add(new AdditionalFixesApplyTask(server)); if (!server.config.launcher.attachLibraryBeforeProGuard) tasks.add(new AttachJarsTask(server)); if (server.config.launcher.compress) tasks.add(new CompressBuildTask(server)); - if(server.config.sign.enabled) tasks.add(new SignJarTask(server.config.sign, server)); + tasks.add(new SignJarTask(server.config.sign, server)); } @Override 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 c06ee91c..4711dcc2 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 @@ -1,8 +1,17 @@ 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.binary.SignerJar; import pro.gravit.launchserver.config.LaunchServerConfig; @@ -12,12 +21,23 @@ import java.io.File; import java.io.IOException; +import java.math.BigInteger; import java.nio.file.Path; import java.security.KeyStore; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.UnrecoverableKeyException; +import java.security.cert.Certificate; import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.security.interfaces.ECPrivateKey; +import java.security.interfaces.ECPublicKey; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.Date; import java.util.jar.Manifest; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; @@ -45,7 +65,12 @@ public Path process(Path inputFile) throws IOException { return toRet; } - public static void sign(LaunchServerConfig.JarSignerConf config, Path inputFile, Path signedFile) throws IOException { + public void sign(LaunchServerConfig.JarSignerConf config, Path inputFile, Path signedFile) throws IOException { + if(config.enabled) stdSign(config, inputFile, signedFile); + else autoSign(inputFile, signedFile); + } + + private void stdSign(LaunchServerConfig.JarSignerConf config, Path inputFile, Path signedFile) throws IOException { KeyStore c = SignHelper.getStore(new File(config.keyStore).toPath(), config.keyStorePass, config.keyStoreType); try (SignerJar output = new SignerJar(new ZipOutputStream(IOHelper.newOutput(signedFile)), () -> SignJarTask.gen(config, c), config.metaInfSfName, config.metaInfKeyName); @@ -64,6 +89,30 @@ public static void sign(LaunchServerConfig.JarSignerConf config, Path inputFile, } } } + 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); + } + }, + "AUTOGEN.SF", "AUTOGEN.EC"); + ZipInputStream input = new ZipInputStream(IOHelper.newInput(inputFile))) { + //input.getManifest().getMainAttributes().forEach((a, b) -> output.addManifestAttribute(a.toString(), b.toString())); // may not work such as after Radon. + ZipEntry e = input.getNextEntry(); + while (e != null) { + if ("META-INF/MANIFEST.MF".equals(e.getName()) || "/META-INF/MANIFEST.MF".equals(e.getName())) { + Manifest m = new Manifest(input); + m.getMainAttributes().forEach((a, b) -> output.addManifestAttribute(a.toString(), b.toString())); + e = input.getNextEntry(); + continue; + } + output.addFileContents(IOHelper.newZipEntry(e), input); + e = input.getNextEntry(); + } + } + } @Override public boolean allowDelete() { @@ -80,4 +129,26 @@ 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"); + } } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/command/service/SignDirCommand.java b/LaunchServer/src/main/java/pro/gravit/launchserver/command/service/SignDirCommand.java index 87ef1c9e..84abd7cf 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/command/service/SignDirCommand.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/command/service/SignDirCommand.java @@ -2,6 +2,7 @@ import pro.gravit.launchserver.LaunchServer; import pro.gravit.launchserver.binary.tasks.SignJarTask; +import pro.gravit.launchserver.binary.tasks.TaskUtil; import pro.gravit.launchserver.command.Command; import pro.gravit.utils.helper.IOHelper; import pro.gravit.utils.helper.LogHelper; @@ -13,13 +14,18 @@ public class SignDirCommand extends Command { private class SignJarVisitor extends SimpleFileVisitor { + private SignJarTask task; + public SignJarVisitor(SignJarTask task) { + this.task = task; + } + @Override public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { if (file.toFile().getName().endsWith(".jar")) { Path tmpSign = server.dir.resolve("build").resolve(file.toFile().getName()); LogHelper.info("Signing jar %s", file.toString()); - SignJarTask.sign(server.config.sign, file, tmpSign); + task.sign(server.config.sign, file, tmpSign); Files.deleteIfExists(file); Files.move(tmpSign, file); } @@ -46,7 +52,8 @@ public void invoke(String... args) throws Exception { Path targetDir = Paths.get(args[0]); if(!IOHelper.isDir(targetDir)) throw new IllegalArgumentException(String.format("%s not directory", targetDir.toString())); - IOHelper.walk(targetDir, new SignJarVisitor(), true); + SignJarTask task = (SignJarTask) TaskUtil.getTaskByClass(server.launcherBinary.tasks, SignJarTask.class); + IOHelper.walk(targetDir, new SignJarVisitor(task), true); LogHelper.info("Success signed"); } } diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/command/service/SignJarCommand.java b/LaunchServer/src/main/java/pro/gravit/launchserver/command/service/SignJarCommand.java index 57c202e6..62162f60 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/command/service/SignJarCommand.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/command/service/SignJarCommand.java @@ -2,6 +2,7 @@ import pro.gravit.launchserver.LaunchServer; import pro.gravit.launchserver.binary.tasks.SignJarTask; +import pro.gravit.launchserver.binary.tasks.TaskUtil; import pro.gravit.launchserver.command.Command; import pro.gravit.utils.helper.LogHelper; @@ -34,7 +35,8 @@ public void invoke(String... args) throws Exception { else tmpSign = server.dir.resolve("build").resolve(target.toFile().getName()); LogHelper.info("Signing jar %s to %s", target.toString(), tmpSign.toString()); - SignJarTask.sign(server.config.sign, target, tmpSign); + SignJarTask task = (SignJarTask) TaskUtil.getTaskByClass(server.launcherBinary.tasks, SignJarTask.class); + task.sign(server.config.sign, target, tmpSign); if(args.length <= 1) { LogHelper.info("Move temp jar %s to %s", tmpSign.toString(), target.toString()); diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/config/LaunchServerConfig.java b/LaunchServer/src/main/java/pro/gravit/launchserver/config/LaunchServerConfig.java index 5f42a71b..ecb3ffaf 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/config/LaunchServerConfig.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/config/LaunchServerConfig.java @@ -227,7 +227,7 @@ public static class CertificateConf { } public static class JarSignerConf { - public boolean enabled = true; + public boolean enabled = false; public String keyStore = "pathToKey"; public String keyStoreType = "JKS"; public String keyStorePass = "mypass"; diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/helper/SignHelper.java b/LaunchServer/src/main/java/pro/gravit/launchserver/helper/SignHelper.java index 896d6f2c..a66f588e 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/helper/SignHelper.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/helper/SignHelper.java @@ -144,6 +144,17 @@ public static CMSSignedDataGenerator createSignedDataGenerator(KeyStore keyStore generator.addCertificates(certStore); return generator; } + public static CMSSignedDataGenerator createSignedDataGenerator(PrivateKey privateKey, Certificate cert, List certChain, String signAlgo) throws OperatorCreationException, CertificateEncodingException, CMSException { + @SuppressWarnings("rawtypes") + Store certStore = new JcaCertStore(certChain); + ContentSigner signer = new JcaContentSignerBuilder(signAlgo).setProvider("BC").build(privateKey); + CMSSignedDataGenerator generator = new CMSSignedDataGenerator(); + DigestCalculatorProvider dcp = new JcaDigestCalculatorProviderBuilder().setProvider("BC").build(); + SignerInfoGenerator sig = new JcaSignerInfoGeneratorBuilder(dcp).build(signer, (X509Certificate) cert); + generator.addSignerInfoGenerator(sig); + generator.addCertificates(certStore); + return generator; + } public static final String hashFunctionName = "SHA-256"; diff --git a/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/CertificateManager.java b/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/CertificateManager.java index f14c4069..71fad349 100644 --- a/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/CertificateManager.java +++ b/LaunchServer/src/main/java/pro/gravit/launchserver/manangers/CertificateManager.java @@ -81,7 +81,7 @@ public X509CertificateHolder generateCertificate(String subjectName, PublicKey s } public void generateCA() throws NoSuchAlgorithmException, IOException, OperatorCreationException, InvalidAlgorithmParameterException { - ECGenParameterSpec ecGenSpec = new ECGenParameterSpec("secp384r1"); + ECGenParameterSpec ecGenSpec = new ECGenParameterSpec("secp384k1"); KeyPairGenerator generator = KeyPairGenerator.getInstance("EC"); generator.initialize(ecGenSpec, SecurityHelper.newRandom()); KeyPair pair = generator.generateKeyPair(); @@ -105,7 +105,7 @@ public void generateCA() throws NoSuchAlgorithmException, IOException, OperatorC } public KeyPair generateKeyPair() throws InvalidAlgorithmParameterException, NoSuchAlgorithmException { - ECGenParameterSpec ecGenSpec = new ECGenParameterSpec("secp384r1"); + ECGenParameterSpec ecGenSpec = new ECGenParameterSpec("secp384k1"); KeyPairGenerator generator = KeyPairGenerator.getInstance("EC"); generator.initialize(ecGenSpec, SecurityHelper.newRandom()); return generator.generateKeyPair();