mirror of
https://github.com/GravitLauncher/Launcher
synced 2024-12-23 00:51:01 +03:00
[FEATURE] Автогенерация сертификата на лету при его отсутствии
This commit is contained in:
parent
585fb06151
commit
625fb75f82
7 changed files with 99 additions and 8 deletions
|
@ -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
|
||||
|
|
|
@ -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<Certificate> chain = new ArrayList<>();
|
||||
chain.add(x509Certificate);
|
||||
return SignHelper.createSignedDataGenerator(privateKey, x509Certificate, chain, "SHA256WITHECDSA");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Path>
|
||||
{
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -144,6 +144,17 @@ public static CMSSignedDataGenerator createSignedDataGenerator(KeyStore keyStore
|
|||
generator.addCertificates(certStore);
|
||||
return generator;
|
||||
}
|
||||
public static CMSSignedDataGenerator createSignedDataGenerator(PrivateKey privateKey, Certificate cert, List<Certificate> 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";
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in a new issue