我准备了一个应用程序和网站,客户可以在其中为该应用程序设置几个选项,然后再下载它。设置以二进制格式存储在文件末尾(附加),然后将编辑后的文件发送给最终用户。问题是文件“内容”的更改会破坏文件签名 - 是否有机会使用任何命令行工具重新签署这个更改的文件?我尝试使用 Microsoft 的 SignTool,但它在 Linux 上无法正常工作。
3 回答
你可以试试osslsigncode
要签署 EXE 或 MSI 文件,您现在可以执行以下操作:
osslsigncode sign -certs <cert-file> -key <der-key-file> \
-n "Your Application" -i http://www.yourwebsite.com/ \
-in yourapp.exe -out yourapp-signed.exe
或者,如果您使用带有密码的 PEM 或 PVK 密钥文件以及 PEM 证书:
osslsigncode sign -certs <cert-file> \
-key <key-file> -pass <key-password> \
-n "Your Application" -i http://www.yourwebsite.com/ \
-in yourapp.exe -out yourapp-signed.exe
或者如果您还想添加时间戳:
osslsigncode sign -certs <cert-file> -key <key-file> \
-n "Your Application" -i http://www.yourwebsite.com/ \
-t http://timestamp.verisign.com/scripts/timstamp.dll \
-in yourapp.exe -out yourapp-signed.exe
您可以使用存储在 PKCS#12 容器中的证书和密钥:
osslsigncode sign -pkcs12 <pkcs12-file> -pass <pkcs12-password> \
-n "Your Application" -i http://www.yourwebsite.com/ \
-in yourapp.exe -out yourapp-signed.exe
签署包含 java 类文件的 CAB 文件:
osslsigncode sign -certs <cert-file> -key <key-file> \
-n "Your Application" -i http://www.yourwebsite.com/ \
-jp low \
-in yourapp.cab -out yourapp-signed.cab
使用's signtool实际上很简单;Mono
棘手的部分(在链接的 Mozilla 文章中更详细地描述)是以正确的格式将证书从 Windows 复制到 Linux。
将 Windows PFX 证书文件转换为 PVK 和 SPC 文件,只需在将证书从 Windows 复制到 Linux 时进行一次;
openssl pkcs12 -in authenticode.pfx -nocerts -nodes -out key.pem
openssl rsa -in key.pem -outform PVK -pvk-strong -out authenticode.pvk
openssl pkcs12 -in authenticode.pfx -nokeys -nodes -out cert.pem
openssl crl2pkcs7 -nocrl -certfile cert.pem -outform DER -out authenticode.spc
实际上签署 exe 是直截了当的;
signcode \
-spc authenticode.spc \
-v authenticode.pvk \
-a sha1 -$ commercial \
-n My\ Application \
-i http://www.example.com/ \
-t http://timestamp.digicert.com/scripts/timstamp.dll \
-tr 10 \
MyApp.exe
如果您想在运行时以编程方式执行此操作,您可以使用Jsign工具。特别是当您通过请求签名在后端生成自可执行存档时,它可能会非常有用。你显然使用 Java/Kotlin 来做到这一点(工具的名称是建议的)。这是官方网站提供的API:
只需将此依赖项添加到项目中:
<dependency> <groupId>net.jsign</groupId> <artifactId>jsign-core</artifactId> <version>3.1</version> </dependency>
然后
AuthenticodeSigner
像这样使用类: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);
有关 API 的更多详细信息,请参阅Javadoc。
除了通过 Java 签名之外,KeyStore
AuthenticodeSigner
还有(Certificate, PrivateKey)
构造函数,你可以像我在“Kotlin 上的 Spring”后端那样自由地使用它:
@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");
之后,您可以只@Autowire
使用bean 并使用所需文件signer
调用其方法sign()