diff --git a/asm/src/main/java/dev/openrs2/asm/classpath/Library.kt b/asm/src/main/java/dev/openrs2/asm/classpath/Library.kt index 212c3eeb91..6f86099402 100644 --- a/asm/src/main/java/dev/openrs2/asm/classpath/Library.kt +++ b/asm/src/main/java/dev/openrs2/asm/classpath/Library.kt @@ -101,8 +101,14 @@ class Library constructor() : Iterable { val unsignedPath = Files.createTempFile("tmp", ".jar") try { writeJar(classPath, unsignedPath, manifest) - keyStore.signJar(unsignedPath) - DeterministicJarOutputStream.repack(unsignedPath, path) + + val signedPath = Files.createTempFile("tmp", ".jar") + try { + keyStore.signJar(unsignedPath, signedPath) + DeterministicJarOutputStream.repack(signedPath, path) + } finally { + Files.deleteIfExists(signedPath) + } } finally { Files.deleteIfExists(unsignedPath) } diff --git a/common/src/main/java/dev/openrs2/common/crypto/Pkcs12KeyStore.kt b/common/src/main/java/dev/openrs2/common/crypto/Pkcs12KeyStore.kt index 27a6d6c7c2..973c31c37f 100644 --- a/common/src/main/java/dev/openrs2/common/crypto/Pkcs12KeyStore.kt +++ b/common/src/main/java/dev/openrs2/common/crypto/Pkcs12KeyStore.kt @@ -1,5 +1,6 @@ package dev.openrs2.common.crypto +import jdk.security.jarsigner.JarSigner import org.bouncycastle.asn1.nist.NISTObjectIdentifiers import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers import org.bouncycastle.asn1.x500.X500NameBuilder @@ -10,7 +11,6 @@ import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter import org.bouncycastle.crypto.util.SubjectPublicKeyInfoFactory import org.bouncycastle.operator.bc.BcRSAContentSignerBuilder import org.bouncycastle.util.BigIntegers -import java.io.IOException import java.nio.file.Files import java.nio.file.Path import java.security.KeyFactory @@ -19,18 +19,21 @@ import java.time.OffsetDateTime import java.time.Period import java.time.ZoneOffset import java.util.Date - -class Pkcs12KeyStore private constructor(private val path: Path) { - fun signJar(jar: Path) { - exec( - "jarsigner", - "-keystore", path.toString(), - "-storetype", "pkcs12", - "-storepass", PASSWORD, - "-keypass", PASSWORD, - jar.toString(), - ALIAS - ) +import java.util.jar.JarFile + +class Pkcs12KeyStore private constructor(privateKeyEntry: KeyStore.PrivateKeyEntry) { + private val signer = JarSigner.Builder(privateKeyEntry) + .signatureAlgorithm("SHA256withRSA") + .digestAlgorithm("SHA-256") + .signerName(SIGNER_NAME) + .build() + + fun signJar(input: Path, output: Path) { + JarFile(input.toFile()).use { file -> + Files.newOutputStream(output).use { os -> + signer.sign(file, os) + } + } } companion object { @@ -43,8 +46,9 @@ class Pkcs12KeyStore private constructor(private val path: Path) { private const val SERIAL_LENGTH = 128 // TODO(gpe): add support for overriding this + private const val SIGNER_NAME = "OpenRS2" private val DNAME = X500NameBuilder() - .addRDN(BCStyle.CN, "OpenRS2") + .addRDN(BCStyle.CN, SIGNER_NAME) .build() private val MAX_CLOCK_SKEW = Period.ofDays(1) @@ -63,15 +67,20 @@ class Pkcs12KeyStore private constructor(private val path: Path) { keyStore.load(null) } - if (!keyStore.containsAlias(ALIAS)) { - keyStore.setEntry(ALIAS, createPrivateKeyEntry(), PASSWORD_PARAMETER) + val privateKeyEntry = if (keyStore.containsAlias(ALIAS)) { + keyStore.getEntry(ALIAS, PASSWORD_PARAMETER) as KeyStore.PrivateKeyEntry + } else { + val entry = createPrivateKeyEntry() + keyStore.setEntry(ALIAS, entry, PASSWORD_PARAMETER) Files.newOutputStream(path).use { output -> keyStore.store(output, PASSWORD_CHARS) } + + entry } - return Pkcs12KeyStore(path) + return Pkcs12KeyStore(privateKeyEntry) } private fun createPrivateKeyEntry(): KeyStore.PrivateKeyEntry { @@ -98,15 +107,5 @@ class Pkcs12KeyStore private constructor(private val path: Path) { val jcaCertificate = JcaX509CertificateConverter().getCertificate(certificate) return KeyStore.PrivateKeyEntry(jcaPrivate, arrayOf(jcaCertificate)) } - - private fun exec(command: String, vararg args: String) { - val commandWithArgs = listOf(command, *args) - val status = ProcessBuilder(commandWithArgs) - .start() - .waitFor() - if (status != 0) { - throw IOException("$command returned non-zero status code $status") - } - } } }