If you want to do that programmatically in runtime you can usee Jsign tool. Especially it could be quite helpful when you generate self-executable archive on the backend by request signing it after. And you do that using Java/Kotlin obviously (name of the tool is suggesting). Here is API provided from the official site:
Simply add this dependency to the project:
<dependency>
<groupId>net.jsign</groupId>
<artifactId>jsign-core</artifactId>
<version>3.1</version>
</dependency>
and then use the AuthenticodeSigner
class like this:
KeyStore keystore = KeyStoreUtils.load(newFile("keystore.p12"), "PKCS12", "password", null);
AuthenticodeSigner signer = new AuthenticodeSigner(keystore, "test", "secret"); signer.withProgramName("My Application")
.withProgramURL("http://www.example.com")
.withTimestamping(true)
.withTimestampingAuthority("http://timestamp.comodoca.com/authenticode");
Signable file = Signable.of(new File("application.exe"));
signer.sign(file);
See the Javadoc for more details about the API.
Besides signing via Java KeyStore
AuthenticodeSigner
has (Certificate, PrivateKey)
constructor and you can freely use it like I did in my "Spring on Kotlin" backend:
@Bean
fun certsChain(): Array<Certificate> {
val fact: CertificateFactory = CertificateFactory.getInstance("X.509")
val `is` = ResourceUtil.getResourceFileAsInputStream("cert/certificate.pem")
val cer: X509Certificate = fact.generateCertificate(`is`) as X509Certificate
return arrayOf(cer)
}
@Bean
fun privateKey(): PrivateKey {
var key = ResourceUtil.getResourceFileAsString("cert/privateKey.pem")
key = key.replace("-----BEGIN PRIVATE KEY-----", "")
key = key.replace("\n", "")
key = key.replace("-----END PRIVATE KEY-----", "")
val encoded = Base64.getDecoder().decode(key)
val kf = KeyFactory.getInstance("RSA")
val keySpec = PKCS8EncodedKeySpec(encoded)
return kf.generatePrivate(keySpec) as RSAPrivateKey
}
@Bean
fun signer(
certs: Array<Certificate>,
privateKey: PrivateKey
): AuthenticodeSigner =
AuthenticodeSigner(certs, privateKey)
.withProgramName("Your Company Name")
.withProgramURL("https://something.com")
.withTimestamping(true)
.withTimestampingAuthority("http://timestamp.comodoca.com/authenticode");
after, you can just @Autowire
the signer
bean and call its method sign()
with the required file