31

我准备了一个应用程序和网站,客户可以在其中为该应用程序设置几个选项,然后再下载它。设置以二进制格式存储在文件末尾(附加),然后将编辑后的文件发送给最终用户。问题是文件“内容”的更改会破坏文件签名 - 是否有机会使用任何命令行工具重新签署这个更改的文件?我尝试使用 Microsoft 的 SignTool,但它在 Linux 上无法正常工作。

4

3 回答 3

44

你可以试试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
于 2015-03-16T09:59:21.920 回答
30

使用'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
于 2013-08-17T11:03:21.197 回答
1

如果您想在运行时以编程方式执行此操作,您可以使用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()

于 2020-05-11T21:21:18.520 回答