ebourg / jsign

Java implementation of Microsoft Authenticode for signing Windows executables, installers & scripts
https://ebourg.github.io/jsign
Apache License 2.0
250 stars 107 forks source link

BattlEye validation issue due to missing intermediate certificates #217

Closed vinnyvinny1989 closed 1 month ago

vinnyvinny1989 commented 1 month ago

Hello all. First of all, thank you for your work. I'm trying to use jsign to sign files, but I have a problem that I can't solve.

I have Sectico hardware token. My files must be signed to work with Battleye anti-cheat program.

The problem is, when i sign files using Microsoft signtool, everything is ok. Command to sign: signtool sign /s my /as /fd SHA256 /tr http://timestamp.sectigo.com important_file.exe

But when I'm trying to use jsign, Battleye shows me the error message. Command to sign: jsign --storetype ETOKEN -d SHA-256 --storepass <password here> -t http://timestamp.sectigo.com important_file.exe

Battleye told me that the problem is that the files are signed by jsign don't have certificate chain. So they can't pass their validation. Maybe someone can tell me what parameters I need to enter to sign a file with a certificate chain?

I also noticed that the files are signed by jsign are smaller than files are signed by signtool (screenshot in attachment). I would really like to use jsign instead of signtool because with jsign I can specify password directly in sign command, and add sign system to CI/CD jsign_signtool_diffrence .

ebourg commented 1 month ago

The signature added to the file contains the certificate chain. signtool puts the whole chain in the signature, but the root certificate doesn't have to be included since it's already in the Windows truststore. For this reason Jsign doesn't put the root certificate in the signature and that's why the signed file is smaller.

Is the signature valid in the Digital Signatures tab of the Windows file properties? If so then that's a flaw in the Battleye verification algorithm.

If you don't mind rebuilding Jsign (with mvn package -DskipTests) you can modify the isSelfSigned() method in the AuthenticodeSigner class to always return false and see if that makes a difference with Battleye.

vinnyvinny1989 commented 1 month ago

I tried to compile jsign with isSelfSigned() method which return false and sign file. Unfortunately without success. Result file was the same size as before.

Also, I'm not very strong in coding, was it correct? private boolean isSelfSigned(X509Certificate certificate) { return false; }

ebourg commented 1 month ago

Yes that's correct. And after building the project you've used java -jar jsign\target\jsign-6.1-SNAPSHOT.jar --storetype ETOKEN ... ?

By disabling isSelfSigned()you should get a larger file, unless the certificate chain stored on the eToken contains only one certificate, but in this case Windows should tell you that the signature is invalid.

vinnyvinny1989 commented 1 month ago

Yes, my command was java -jar jsign-6.1-SNAPSHOT.jar --storetype ETOKEN -d SHA-256 --storepass <password here> -t http://timestamp.sectigo.com important_file.exe

About file sizes: filesizes_comparsion

ebourg commented 1 month ago

Could you send the two files signed by signtool and jsign to ebourg@apache.org? I'll give them a look.

vinnyvinny1989 commented 1 month ago

I wrote you an email.

Also, Battleye gave me the trick how to avoid this issue.

  1. sign the file with signtool
  2. export *.p7b certificate from file
  3. sign another file with --certfile option

And voila, the problem has been solved, Battleye verification passed. Maybe this will be useful to someone. But if signtool can do it without exported *.p7b it will be more convenient to add this features to jsign

jsign --storetype ETOKEN -d SHA-256 --storepass <password here> --certfile exported_cert.p7b -t http://timestamp.sectigo.com important_file.exe

j74cgVKudXLZ0NUh
ebourg commented 1 month ago

Thank you for the files.

The file signed by signtool contains 6 certificates:

So I was wrong when I said that signtool adds the root certificates to the signature, and tweaking isSelfSigned() cannot have any effect on this issue.

The file signed by Jsign contains 4 certificates:

So it seems the issue is caused by the lack of the 2 intermediate certificates (Sectigo Public Code Signing CA EV R36, Sectigo Public Code Signing Root R46) from the signature generated by Jsign. Since these certificates are in the Windows truststore the signature is considered valid by Windows. But external verification tools will fail to validate the signature if they don't have a similar list of intermediate certificates.

On the BattlEye side, they should pull the intermediate CA certificates from the Windows truststore when validating files, and not just the list of root CA. That's definitely an issue worth reporting.

On the Jsign side, it would be nice if the signing certificate chain could be completed automatically with the missing intermediate certificates similarly to signtool. But since Jsign is cross-plaform and cannot fetch the certificates from the Windows truststore, the list of certificates will have to be bundled with Jsign. This will be useful for implementing the verification feature anyway. Ther list of root and intermediate CA certificates is available from the Common CA database.

In the meantime, the workaround is to set the --certfile parameter pointing to a file containing the two intermediate certificates:

-----BEGIN CERTIFICATE-----
MIIGGjCCBAKgAwIBAgIQYh1tDFIBnjuQeRUgiSEcCjANBgkqhkiG9w0BAQwFADBW
MQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMS0wKwYDVQQD
EyRTZWN0aWdvIFB1YmxpYyBDb2RlIFNpZ25pbmcgUm9vdCBSNDYwHhcNMjEwMzIy
MDAwMDAwWhcNMzYwMzIxMjM1OTU5WjBUMQswCQYDVQQGEwJHQjEYMBYGA1UEChMP
U2VjdGlnbyBMaW1pdGVkMSswKQYDVQQDEyJTZWN0aWdvIFB1YmxpYyBDb2RlIFNp
Z25pbmcgQ0EgUjM2MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAmyud
U/o1P45gBkNqwM/1f/bIU1MYyM7TbH78WAeVF3llMwsRHgBGRmxDeEDIArCS2VCo
Vk4Y/8j6stIkmYV5Gej4NgNjVQ4BYoDjGMwdjioXan1hlaGFt4Wk9vT0k2oWJMJj
L9G//N523hAm4jF4UjrW2pvv9+hdPX8tbbAfI3v0VdJiJPFy/7XwiunD7mBxNtec
M6ytIdUlh08T2z7mJEXZD9OWcJkZk5wDuf2q52PN43jc4T9OkoXZ0arWZVeffvMr
/iiIROSCzKoDmWABDRzV/UiQ5vqsaeFaqQdzFf4ed8peNWh1OaZXnYvZQgWx/SXi
JDRSAolRzZEZquE6cbcH747FHncs/Kzcn0Ccv2jrOW+LPmnOyB+tAfiWu01TPhCr
9VrkxsHC5qFNxaThTG5j4/Kc+ODD2dX/fmBECELcvzUHf9shoFvrn35XGf2RPaNT
O2uSZ6n9otv7jElspkfK9qEATHZcodp+R4q2OIypxR//YEb3fkDn3UayWW9bAgMB
AAGjggFkMIIBYDAfBgNVHSMEGDAWgBQy65Ka/zWWSC8oQEJwIDaRXBeF5jAdBgNV
HQ4EFgQUDyrLIIcouOxvSK4rVKYpqhekzQwwDgYDVR0PAQH/BAQDAgGGMBIGA1Ud
EwEB/wQIMAYBAf8CAQAwEwYDVR0lBAwwCgYIKwYBBQUHAwMwGwYDVR0gBBQwEjAG
BgRVHSAAMAgGBmeBDAEEATBLBgNVHR8ERDBCMECgPqA8hjpodHRwOi8vY3JsLnNl
Y3RpZ28uY29tL1NlY3RpZ29QdWJsaWNDb2RlU2lnbmluZ1Jvb3RSNDYuY3JsMHsG
CCsGAQUFBwEBBG8wbTBGBggrBgEFBQcwAoY6aHR0cDovL2NydC5zZWN0aWdvLmNv
bS9TZWN0aWdvUHVibGljQ29kZVNpZ25pbmdSb290UjQ2LnA3YzAjBggrBgEFBQcw
AYYXaHR0cDovL29jc3Auc2VjdGlnby5jb20wDQYJKoZIhvcNAQEMBQADggIBAAb/
guF3YzZue6EVIJsT/wT+mHVEYcNWlXHRkT+FoetAQLHI1uBy/YXKZDk8+Y1LoNqH
rp22AKMGxQtgCivnDHFyAQ9GXTmlk7MjcgQbDCx6mn7yIawsppWkvfPkKaAQsiqa
T9DnMWBHVNIabGqgQSGTrQWo43MOfsPynhbz2Hyxf5XWKZpRvr3dMapandPfYgoZ
8iDL2OR3sYztgJrbG6VZ9DoTXFm1g0Rf97Aaen1l4c+w3DC+IkwFkvjFV3jS49ZS
c4lShKK6BrPTJYs4NG1DGzmpToTnwoqZ8fAmi2XlZnuchC4NPSZaPATHvNIzt+z1
PHo35D/f7j2pO1S8BCysQDHCbM5Mnomnq5aYcKCsdbh0czchOm8bkinLrYrKpii+
Tk7pwL7TjRKLXkomm5D1Umds++pip8wH2cQpf93at3VDcOK4N7EwoIJB0kak6pSz
Eu4I64U6gZs7tS/dGNSljf2OSSnRr7KWzq03zl8l75jy+hOds9TWSenLbjBQUGR9
6cFr6lEUfAIEHVC1L68Y1GGxx4/eRI82ut83axHMViw1+sVpbPxg51Tbnio1lB93
079WPFnYaOvfGAA0e0zcfF/M9gXr+korwQTh2Prqooq2bYNMvUoUKD85gnJ+t0sm
rWrb8dee2CvYZXD5laGtaAxOfy/VKNmwuWuAh9kc
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIFeDCCA2CgAwIBAgIQSyw7AQGLrSq8jHtbPu2QVzANBgkqhkiG9w0BAQwFADBW
MQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMS0wKwYDVQQD
EyRTZWN0aWdvIFB1YmxpYyBDb2RlIFNpZ25pbmcgUm9vdCBSNDYwHhcNMjEwMzIy
MDAwMDAwWhcNNDYwMzIxMjM1OTU5WjBWMQswCQYDVQQGEwJHQjEYMBYGA1UEChMP
U2VjdGlnbyBMaW1pdGVkMS0wKwYDVQQDEyRTZWN0aWdvIFB1YmxpYyBDb2RlIFNp
Z25pbmcgUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCN
55QSIgQkdC7/FiMCkoq2rjaFrEfUI5ErPtx94jGgUW+shJHjUoq14pbe0IdjJImK
/+8Skzt9u7aKvb0Ffyeba2XTpQxpsbxJOZrxbW6q5KCDJ9qaDStQ6Utbs7hkNqR+
Sj2pcaths3OzPAsM79szV+W+NDfjlxtd/R8SPYIDdub7P2bSlDFp+m2zNKzBenjc
klDyZMeqLQSrw2rq4C+np9xu1+j/2iGrQL+57g2extmeme/G3h+pDHazJyCh1rr9
gOcB0u/rgimVcI3/uxXP/tEPNqIuTzKQdEZrRzUTdwUzT2MuuC3hv2WnBGsY2HH6
zAjybYmZELGt2z4s5KoYsMYHAXVn3m3pY2MeNn9pib6qRT5uWl+PoVvLnTCGMOgD
s0DGDQ84zWeoU4j6uDBl+m/H5x2xg3RpPqzEaDux5mczmrYI4IAFSEDu9oJkRqj1
c7AGlfJsZZ+/VVscnFcax3hGfHCqlBuCF6yH6bbJDoEcQNYWFyn8XJwYK+pF9e+9
1WdPKF4F7pBMeufG9ND8+s0+MkYTIDaKBOq3qgdGnA2TOglmmVhcKaO5DKYwODzQ
RjY1fJy67sPV+Qp2+n4FG0DKkjXp1XrRtX8ArqmQqsV/AZwQsRb8zG4Y3G9i/qZQ
p7h7uJ0VP/4gDHXIIloTlRmQAOka1cKG8eOO7F/05QIDAQABo0IwQDAdBgNVHQ4E
FgQUMuuSmv81lkgvKEBCcCA2kVwXheYwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB
/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAHZlwuPXIkrXHYle/2lexhQCTXOm
zc0oyrA36r+nySGqql/av/aDbNCA0QpcAKTL88w5D55BcYjVPOiKe4wXI/fKNHSR
bAauUD8AWbImPDwXg1cDPi3RGj3UzwdUskMLUnKoiPXEF/Jv0Vil0WjkPZgIGO42
9EhImvpUcPCI1HAWMEJJ0Nk/dUtFcdiuorthDoiFUFe5uhErNikfjyBynlyeidGC
2kWNapnahHFrM6UQu3nwl/Z0gaA/V8eGjDCMDjiVrgHGHqvcqB9vL9f/dh6uF3Nt
5bl1s2EGqJUzwk5vsjfylb6FVBK5yL1iQnb3Kvz1NzEDJlf+0ebb8BYCcoOMCLOE
rKnkB/ihiMQTWlBHVEKm7dBBNCyYsT6iNKEMXb2s9395p79tDFYyhRtLl7jhrOSk
PHHxo+FOY9b0Rrr1CwjhYzztolkvCtQsayOinqFN7tESzRgzUO1Bbst/PUFgC2ML
ePV170MVtzYLEK/cXBipmNk22R3YhLMGioLjexskp0LO7g8+VlwyfexL3lYrOzu6
+XpY0FG2bNb2WKJSJHpEhqEcYD9J0/z6+YQcBcI0v+Lm8RkqmS9WVzWctfUHw0Yv
3jg9GQ37o/HfE57nqXJYMa+96trX1m13MzOO9Kz9wb9Jh9JwBWd0Bqb2eEAtFgSR
Dx/TFsS4ehcNJMmy
-----END CERTIFICATE-----
ebourg commented 1 month ago

Alternatively, if you can load the full certificate chain on the SafeNet eToken you could avoid the --certfile parameter. I don't know if that's possible though.

ebourg commented 1 month ago

Digging further, I thought Windows had a list a intermediate CA certificates but I was wrong. Windows adds the intermediate certificates automatically to its trustsore as it discovers them. It does that by fetching the parent certificates using the URL from the authorityInfoAccess field (OID 1.3.6.1.5.5.7.1.1) of the certificate.

This means Jsign could complete the certificate chain automatically. That would remove the need to set the --certfile parameter for all USB tokens that can only store the signing certificate and not the whole chain.

vinnyvinny1989 commented 1 month ago

Thank you for your work and explanation. I also sent a link to the issue to the BattlEye team, they might find it interesting too.

vinnyvinny1989 commented 1 month ago

The BattlEye team wrote me:

the API we use should process the whole chain automatically, but it returns the error of incomplete certificate chain in this case. So it appears some intermediate certificates are not stored on the system (under the system service account which BE runs under) yet and as we found, this failure then happens because for compatibility reasons (sometimes we encountered timeouts, etc.) we do not use AIA retrieval (i.e. downloading intermediate certificates from the internet). So I don't think we can solve this from our end currently.

ebourg commented 1 month ago

@vinnyvinny1989 The missing intermediate certificates are now downloaded automatically. Could you give it a try an confirm it works for you please?

vinnyvinny1989 commented 1 month ago

@vinnyvinny1989 The missing intermediate certificates are now downloaded automatically. Could you give it a try an confirm it works for you please?

To do this I need to rebuild jsign from master branch?

ebourg commented 1 month ago

Yes, or you can download the CI build: https://github.com/ebourg/jsign/actions/runs/9038916734/artifacts/1492735001

vinnyvinny1989 commented 1 month ago

Yes, or you can download the CI build: https://github.com/ebourg/jsign/actions/runs/9038916734/artifacts/1492735001

Confirmed. Everything works well. Thank for your work again!

ebourg commented 1 month ago

Great! Thank you for the feedback