jsign
jsign copied to clipboard
Add ability to sign with additional certificates
Various other signing tools offer the ability to sign with additional certificates:
Sign command option | Description |
---|---|
/ac file | Adds an additional certificate from file to the signature block. |
Sign command option | Description |
---|---|
--additional-certificates [short: -ac, required: no] | A list of paths to additional certificates to aide in building a full chain for the signing certificate. Azure SignTool will build a chain, either as deep as it can or to a trusted root. This will also use the Windows certificate store, in addition to any certificates specified with this option. Specifying this option does not guarantee the inclusion of the certificate, only if it is part of the chain. To include multiple certificates, specify this option mulitple times, such as -ac file1.cer -ac file2.cer. The files specified must be public certificates only. They cannot be PFX, PKCS12 or PFX files. |
It would be great if jsign
also had this ability.
Did you try the certfile
parameter? This allows you to define the certificates added to the signature.
One issue (or difference) I noticed with some tools like jarsigner (used for signing Java archives, and which has a -certchain
option too) is that jsign has check to confirm that the public key certificate from the keystore matches the first certificate of the chain.
IMHO this check may be too strong (better would be to check that the public key of the certificate matches the public key used for signing) and I'm running into a situation where I cannot use Google KMS pkcs11 library for signing with jsign because certificates are autogenerated (I'm aware of the existing GOOGLECLOUD
provider but the lack of support for application default credentials is a blocker for my use-case)
I'm happy to propose a patch to at least add an option to skip the check
@laurentgo thank you for the PRs, I'll give them a look. Could you elaborate on the credentials issue with Google KMS?
@laurentgo I've checked the documentation about application default credentials, have you tried getting an access token with gcloud auth application-default print-access-token
and use it for the storepass
argument?
https://cloud.google.com/sdk/gcloud/reference/auth/application-default/print-access-token
I guess there's nothing wrong with gcloud
command, it's just that our security policies recommend using ADC and not exposing password as arguments, so using GoogleKMS type with jsign is not an option for now, while using libkmsp11
(which supports ADC) as a PKCS#11 provider for jsign doesn't have this authentication issue (but requires an alternative certificate chain).
One nice thing I discovered is that Google has extensive documentation regarding how ADC is supposed to work from an implementation point of view: https://google.aip.dev/auth/4110 Now, this is probably hard/time consuming to implement vs simply using google libraries (but I can understand this is probably not something jsign want to do).
Technically the access token is not a password, but if your security policies prohibit using it as a command line argument it's possible to read the token from an environment variable, and the actual value never appears as an argument:
GOOGLE_ACCESS_TOKEN=$(gcloud auth application-default print-access-token)
jsign --storetype GOOGLECLOUD --storepass env:GOOGLE_ACCESS_TOKEN ...
Would that work for you?
Possibly (would have to check with our team)? But we would definitively favor a solution relying on ADC mechanism for sure.
That said, I don't want to distract from the original ask which is the ability to add additional certificates and/or use a different certificate chain. If you could have a look at my proposal, it would be much appreciated. And I'd gladly open a separate issue regarding Google authentication.
If I understand well, adding extra certificates is useful in a cross signing scenario, when the same key is used by several certificates with different trust paths, right?
correct
Did you try the
certfile
parameter? This allows you to define the certificates added to the signature.
Sorry I haven't managed to test this yet! I'll be back working on the part of our CI that uses jsign in a week or two and will test then :-)
@ebourg do you think you would have time to also provide feedback on my proposed changes (#128 and #129)?
@ebourg - an update on using -certfile
:
Currently we are pulling in an EV cert from Azure and using --storetype AZUREKEYVAULT
. Using --certfile
doesn't work, as we end up with:
jsign: The certificate chain in cert.p7b does not match the chain from the keystore
It is expected that the additional cert is not related at all.
For comparison, using signtool
with an EV cert and the additional certificate in cer format works.
@MrAlex94 Does that mean that when you renew your certificate, you reuse the same private key and update the certificate chain used by the build script, but you do not update the certificate stored in Azure Key Vault?
@ebourg, no, everything gets updated and changed. The additional certificate (such as when using /ac
with signtool.exe
) is completely unrelated to the EV one.
@MrAlex so you basically have two certificate chains, one EV, and the other non-EV, both sharing the same private key hosted by Azure Key Vault? I'd be curious to know the use case behind this.
@mralex so you basically have two certificate chains, one EV, and the other non-EV, both sharing the same private key hosted by Azure Key Vault? I'd be curious to know the use case behind this.
Apologies, my explanation was a bit poor. Essentially, the other certificate is a dummy certificate (unrelated and not hosted at all on Azure), used for partner builds of a program we have. You can see rationale/usage here:
This method uses a hand-crafted dummy certificate that intentionally isn't good for signing anything (it's self-signed, and expired), but that includes a big empty space where you can drop in arbitrary data. Add in that certificate at signing time (using osslsigncode's -ac option), and then that space can be filled in later with the attribution code/other data. The real signing certificate is still present as well, and it gets accepted by Authenticode as usual.
Basically when a user comes from a marketing campaign, we inject the campaign data into the "empty" cert space so we can attribute it nicely.
@MrAlex94 Thank you for the clarification. osslsigncode supports the -addUnauthenticatedBlob
parameter to inject bytes into the signature that can be altered without invalidating it. That's a simpler alternative than fiddling with the additional certificates. This is a feature I'd like to implement in Jsign as well.
Oh, didn’t know that was an option in osslsigncode
! I wonder if I can get the same results that way.
I’ll give it a test and let you know. Currently I just sign the exe twice, once with the valid cert and once with the dummy. The only difference when using the /ac
flag with signtool is that the dummy cert doesn’t appear in the digital signature list on the file properties (I’m not sure why that’s the case?).
Either way, appreciate your vigilance responding to this issue!
Should this be closed, or changed to be the issue for adding the functionality of addUnauthenticatedBlob
?
The only difference when using the /ac flag with signtool is that the dummy cert doesn’t appear in the digital signature list on the file properties (I’m not sure why that’s the case?)
Because the dummy certificate isn't used for signing, it's simply appended to the certificate store embedded within the signature. This store is used by Windows to link the signing certificate with the CA certificate (this is necessary if some of the intermediate certificates are unknown to Windows). The dummy certificate doesn't participate in the certificate chain and is invisible in the file properties. The signature is simply larger.
The addUnauthenticatedBlob feature is slightly different, it adds an entry into the unauthenticated attributes table of the signature. That's more compact that injecting a whole certificate, but it's visible in the file properties
Should this be closed, or changed to be the issue for adding the functionality of addUnauthenticatedBlob?
No I'm still pondering if /ac is worth implementing, I'm just looking for a good use case. I'm tempted to extend the semantic of the certfile
parameter and simply add all the certificates in this file even if they do not participate in the certificate chain.
/ac is useful for situations like this one:
https://knowledge.digicert.com/solution/authenticode-signature-verification-fails-with-new-timestamping-cross-root.html
DigiCert's TSA seems like the fastest and most reliable by far but they did some sort of screwup and the way to fix it is by adding extra certificates so a path through their temp fix-it cert can be found. I'm not sure why they haven't fixed this situation yet but it seems to still be operative.
@mikehearn Thank you for the example!