Azure / azure-sdk-for-java

This repository is for active development of the Azure SDK for Java. For consumers of the SDK we recommend visiting our public developer docs at https://docs.microsoft.com/java/azure/ or our versioned developer docs at https://azure.github.io/azure-sdk-for-java.
MIT License
2.33k stars 1.97k forks source link

Can the KeyVaultJcaProvider be used in jarsigner with a non-exportable private key? #35677

Closed malmor closed 7 months ago

malmor commented 1 year ago

Query/Question Is there a way to integrate the KeyVaultJcaProvider with jarsigner to sign jar files while the private key is stored safely and non-exportable in Azure Key Vault?

Because of the new requirement that code signing certificates must be stored on a compliant HSM storage we looked at Azure Key Vault. For most of our artifacts we found working integrations with different tools - but not for jar files.

Based on #22105 the AzureKeyVault provider should be able to work with non-exportable keys - but I did not manage to get this working in jarsigner.

My commands looks like this:

jarsigner ^
  -verbose ^
  -keystore NONE ^
  -keypass ' ' ^
  -storetype AzureKeyVault ^
  -storepass ' ' ^
  -providerPath C:\repository\azure-security-keyvault-jca.jar ^
  -providerClass com.azure.security.keyvault.jca.KeyVaultJcaProvider ^
  -J'-Dazure.keyvault.uri=https://[my-uri].vault.azure.net/' ^
  -J'-Dazure.keyvault.client-secret=[my-client-secret]' ^
  -J'-Dazure.keyvault.client-id=[my-client-id]' ^
  -J'-Dazure.keyvault.tenant-id=[my-tenant-id]' ^
  my-unsigned-app.jar ^
  my-certificate-name-in-azure

Can you please advise whether this use case can actually work? This questions somehow aligns with #30659 - because I was not able to find any documentation about this. If it is possible I will gladly create a PR to add an example to the docs!

Why is this not a Bug or a feature Request? As far as I can tell #22105 added support for working with non-exportable keys - so this is not so much about adding a feature but understanding how to configure/implement it.

Setup (please complete the following information if applicable):

vcolin7 commented 1 year ago

Hi @malmor, thanks for reaching out, we'll have eyes on this soon. @backwind1233, @chenrujun can you take a look or route it to the right person? Thanks!

malmor commented 1 year ago

Hey @vcolin7, thanks for the initial triage. Just wanted to check in - do you have any update or timeline on this? Finding a solution for this use-case would help us a lot! Regards, Malte

Netyyyy commented 1 year ago

Hi @malmor , Thank you for reporting this issue. We have received your submission and will take it into consideration. We appreciate your input and will review this matter as soon as possible. Please feel free to provide any additional information or context that you think may be helpful. We'll keep you updated on the progress of our review. Thank you for your contribution to improving our project.

schannaveera1 commented 1 year ago

Hi,

Do we have a resolution on this?

backwind1233 commented 1 year ago

Hi @schannaveera1 Thanks for reaching out.

@schannaveera1 @malmor Could you refer to this guide integrate_keyvault_JCA_provider_with_jarsigner.md to use jarsigner with KeyVaultJcaProvider.

Please reply here if it works for you..

malmor commented 1 year ago

Hey @backwind1233, thanks for writing the documentation!

I will give it a try and keep you posted!

backwind1233 commented 1 year ago

Hello @malmor, do you have any update, does it work for you?

malmor commented 1 year ago

Hello @backwind1233, sorry for the delay. I just tried the steps you documented - but they do not seem to work.

What I did:

jarsigner ^
-keystore NONE ^
-storetype AzureKeyVault ^
-signedjar signerjar.jar ^
maven-filtering-3.3.0.jar ^
"my-code-signing-certificate" ^
-verbose ^
-storepass ' ' ^
-providerPath C:\test\azure-security-keyvault-jca.jar ^
-providerName AzureKeyVault ^
-providerClass com.azure.security.keyvault.jca.KeyVaultJcaProvider ^
-J'-Dazure.keyvault.uri=https://my-vault.vault.azure.net/' ^
-J'-Dazure.keyvault.tenant-id=my-tenant-id' ^
-J'-Dazure.keyvault.client-id=my-client-id' ^
-J'-Dazure.keyvault.client-secret=my-client-secret'

Here are the logs:

jarsigner logs ``` PS C:\test> jarsigner -keystore NONE -storetype AzureKeyVault -signedjar signerjar.jar maven-filtering-3.3.0.jar ... Aug 28, 2023 10:57:15 AM com.azure.security.keyvault.jca.implementation.KeyVaultClient INFO: Using Azure Key Vault: https://my-vault.vault.azure.net/ Aug 28, 2023 10:57:15 AM com.azure.security.keyvault.jca.implementation.utils.AccessTokenUtil getAccessToken INFO: Getting access token using client ID / client secret Aug 28, 2023 10:57:17 AM com.azure.security.keyvault.jca.implementation.KeyVaultClient getKey INFO: Getting key for alias: my-code-signing-certificate Aug 28, 2023 10:57:17 AM com.azure.security.keyvault.jca.implementation.KeyVaultClient getCertificate INFO: Getting certificate for alias: my-code-signing-certificate Aug 28, 2023 10:57:17 AM com.azure.security.keyvault.jca.implementation.KeyVaultClient INFO: Using Azure Key Vault: https://my-vault.vault.azure.net/ Aug 28, 2023 10:57:17 AM com.azure.security.keyvault.jca.implementation.utils.AccessTokenUtil getAccessToken INFO: Getting access token using client ID / client secret Aug 28, 2023 10:57:17 AM com.azure.security.keyvault.jca.implementation.KeyVaultClient getKey INFO: Getting key for alias: my-code-signing-certificate Aug 28, 2023 10:57:18 AM com.azure.security.keyvault.jca.implementation.KeyVaultClient getCertificate INFO: Getting certificate for alias: my-code-signing-certificate Aug 28, 2023 10:57:18 AM com.azure.security.keyvault.jca.implementation.KeyVaultClient INFO: Using Azure Key Vault: https://my-vault.vault.azure.net/ Aug 28, 2023 10:57:18 AM com.azure.security.keyvault.jca.implementation.utils.AccessTokenUtil getAccessToken INFO: Getting access token using client ID / client secret Aug 28, 2023 10:57:18 AM com.azure.security.keyvault.jca.implementation.KeyVaultClient getKey INFO: Getting key for alias: my-code-signing-certificate Aug 28, 2023 10:57:18 AM com.azure.security.keyvault.jca.implementation.KeyVaultClient getCertificate INFO: Getting certificate for alias: my-code-signing-certificate jarsigner error: java.lang.IllegalArgumentException: private key algorithm does not match algorithm of public key in end entity certificate (the 1st in certPath) ```

If I can provide any additional information to help troubleshooting this please ask.

Regards, Malte

backwind1233 commented 1 year ago

@malmor Thank you for your feedback.

@moarychan could you help try this with you machine? We can discuss about it later. cc: @saragluna

jyuenatsolarsoft commented 1 year ago

Hi, I've installed com.azure:azure-security-keyvault-jca:2.7.1 on Oracle JDK 1.8.0_u361, tried out the jarsigner command below and got an error different from the OP. We've contacted MS Support and they directed us back to this issue tracker.

"C:\Program Files\Java\jdk1.8.0_361\bin\jarsigner.exe" -keystore NONE -storetype AzureKeyVault -signedjar my-signed-jar.jar my-jar.jar -verbose -storepass "" -providerName AzureKeyVault -providerClass com.azure.security.keyvault.jca.KeyVaultJcaProvider -J-Dazure.keyvault.uri="\<keyvault-uri>" -J-Dazure.keyvault.tenant-id="\<tenant-id>" -J-Dazure.keyvault.client-id="\<client-id>" -J-Dazure.keyvault.client-secret="\<client-secret>" "\<cert alias>"

jarsigner error: java.lang.RuntimeException: private key is not a DSA or RSA key

Looking at the public key in the certificate properties, it shows RSA(3072 Bits). Any clue of what to look into next? I believe the private key is also not exportable in our scenario.

saragluna commented 1 year ago

@malmor may I ask about your certificate advanced policy configuration?

saragluna commented 1 year ago

@jyuenatsolarsoft what's your certificate advanced policy configuration?

malmor commented 1 year ago

@malmor may I ask about your certificate advanced policy configuration?

Hey @saragluna, we used to following settings:

If there are any other settings that could be interesting please ask. Thanks!

jyuenatsolarsoft commented 1 year ago

@saragluna Here's the advanced policy configuration. Let us know if you need more info.

image

backwind1233 commented 1 year ago

Hello @jyuenatsolarsoft In jarsigner official doc, it supports DSA, RSA and ECDSA by default. You can check here

image

From your log, it seems the jarsigner just can't identify the RSA-HSM as RSA.

image

So,

  1. Could you have a try with RSA instead of RSA-HSM?
  2. If you are still using RSA-HSM, could you specify the algorithms with -sigalg flag?
    • let's say the alg of RSA-HSM is the same with RSA, is SHA256withRSA.
jyuenatsolarsoft commented 1 year ago

@backwind1233 @saragluna

  1. That's not an option. There is a new certificate storage requirement from the industry. The private key cannot leave the HSM, so we cannot try with RAS instead of RSA-HSM. https://knowledge.digicert.com/generalinformation/new-private-key-storage-requirement-for-standard-code-signing-certificates-november-2022.html

  2. I got the following error after adding -sigalg SHA256withRSA to the command. jarsigner error: java.security.SignatureException: private key algorithm is not compatible with signature algorithm

saragluna commented 1 year ago

@malmor and @jyuenatsolarsoft

I agree that the issue lies in the HSM part, I think the current code doesn't support RSA-HSM or EC-HSM. I created this draft PR https://github.com/Azure/azure-sdk-for-java/pull/36648, maybe you guys can help run the JarSignerSample directly to check whether it works with your certificate. With this code, you can debug and see what's wrong.

My initial thought is to change the key type from RSA-HSM to RSA in the KeyVaultClient, because the JarSigner will throw an exception when the algorithm doesn't match:

/**
         * Creates a {@code JarSigner.Builder} object with a private key and
         * a certification path.
         *
         * @param privateKey the private key of the signer.
         * @param certPath the certification path of the signer.
         * @throws IllegalArgumentException if {@code certPath} is empty, or
         *      the {@code privateKey} algorithm does not match the algorithm
         *      of the {@code PublicKey} in the end entity certificate
         *      (the first certificate in {@code certPath}).
         */
        public Builder(PrivateKey privateKey, CertPath certPath) {
List<? extends Certificate> certs = certPath.getCertificates();
            if (certs.isEmpty()) {
                throw new IllegalArgumentException("certPath cannot be empty");
            }
            if (!privateKey.getAlgorithm().equals
                    (certs.get(0).getPublicKey().getAlgorithm())) {
                throw new IllegalArgumentException
                        ("private key algorithm does not match " +
                                "algorithm of public key in end entity " +
                                "certificate (the 1st in certPath)");
            }

If not alg specified, the JarSigner will call SignatureUtil.getDefaultSigAlgForKey to construct the default sig alg for a given key,

public static String getDefaultSigAlgForKey(PrivateKey k) {
        String kAlg = k.getAlgorithm().toUpperCase(Locale.ENGLISH);
        return switch (kAlg) {
            case "DSA" -> "SHA256withDSA";
            case "RSA" -> ifcFfcStrength(KeyUtil.getKeySize(k)) + "withRSA";
            case "EC" -> ecStrength(KeyUtil.getKeySize(k)) + "withECDSA";
            case "EDDSA" -> k instanceof EdECPrivateKey
                    ? ((EdECPrivateKey) k).getParams().getName()
                    : kAlg;
            case "RSASSA-PSS", "ED25519", "ED448" -> kAlg;
            default -> null;
        };
    }

In our case, it will be xxxwithRSA. Since JDK already has built-in signature spi implementations defined in RSASignature, so we should use our provider to override the built-in ones, which will send the content to KV to sign.

The PR is not finalized, but please take a look and try, to see whether it will work.

malmor commented 1 year ago

Hey @saragluna, thanks for looking into this and starting the PR!

I must admit I have zero to no experience with java/jarsigner. Could you outline a bit what "maybe you guys can help run the JarSignerSample directly to check whether it works with your certificate" should mean?

I will happily try this out tomorrow šŸ‘

jyuenatsolarsoft commented 1 year ago

@saragluna Thanks for the prompt reply.

I have no idea how to run the JarSignerSample too. Could you elaborate on that?

saragluna commented 1 year ago

@malmor and @jyuenatsolarsoft that will be a bit challenging. Could you guys let me know once you guys sign the jar, how are you going to verify it so that I can try on my side?

To make things easier for you guys to try the code, I sort-of-forked this repo https://github.com/saragluna/azure-security-kv-jca-fork/tree/main, and you guys can either build the jar directly and use the jarsigner command, or try the code in one of the IDEs.

FYI, for a key length of 3072, the alg should be -sigalg SHA512withRSA.

jyuenatsolarsoft commented 1 year ago

@saragluna

Thanks for setting up the test repo. Appreciated.

With the JCA provider compiled from the test repo, the jarsigner command completed the signing process without errors. However, when we tried to verify the signed jar file with the command "jarsigner -verify", it returned an error indicating the jar was treated as unsigned due to a signature issue.

jar: processEntry: processing block
jar: processEntry caught: java.security.SignatureException: Signature length not correct: got 8 but was expecting 384
jar: done with meta!
jar: nothing to verify!

WARNING: Signature is either not parsable or not verifiable, and the jar will be treated as unsigned. For more information, re-run jarsigner with debug enabled (-J-Djava.security.debug=jar).
malmor commented 1 year ago

Hey @saragluna, thanks for the repo - that helped a lot!

I just tried the beta version and saw the same behaviour as @jyuenatsolarsoft:

PS C:\test> jarsigner -verify -debug -verbose -certs -J'-Djava.security.debug=jar' signed-jar.jar

Command line args: [-verify, -debug, -verbose, -certs, signed-jar.jar] 
jar: beginEntry META-INF/MANIFEST.MF 
jar: beginEntry META-INF/REDACTED.SF
jar: processEntry: processing block
jar: beginEntry META-INF/REDACTED.RSA
jar: processEntry: processing block
jar: processEntry caught: java.security.SignatureException: Signature length not correct: got 8 but was expecting 384 
jar: done with meta!
jar: nothing to verify!

        4748 Tue Sep 12 07:35:38 GMT+02:00 2023 META-INF/MANIFEST.MF
        4678 Tue Sep 12 07:35:38 GMT+02:00 2023 META-INF/REDACTED.SF
        2179 Tue Sep 12 07:35:38 GMT+02:00 2023 META-INF/REDACTED.RSA
           0 Sat Jun 11 13:41:16 GMT+02:00 2022 META-INF/
           0 Sat Jun 11 13:41:16 GMT+02:00 2022 META-INF/sisu/
        ....

- Signed by "CN=Company, OU=Company, O=Company, L=City, C=County"
    Digest algorithm: SHA-384
    Signature algorithm: SHA512withRSA, 3072-bit key

WARNING: Signature is either not parsable or not verifiable, and the jar will be treated as unsigned. For more information, re-run jarsigner with debug enabled (-J-Djava.security.debug=jar).
saragluna commented 1 year ago

Thanks @jyuenatsolarsoft and @malmor for the update, let me check whether it's because of the hash function.

saragluna commented 1 year ago

Hi @jyuenatsolarsoft and @malmor, I just updated the code, maybe you guys can have another try.

hounster commented 1 year ago

@saragluna Thanks for the updates. I've been following this issue as well. I just compiled and tested. Looks encouraging.

NOTE I initially received a duplicate class error on compile and had to remove the following source file:

src/main/java/com/azure/security/keyvault/jca/implementation/signature/KeyVaultKeyLessECSignature.java

For reference I'm using a self-signed certificate with the following advanced policy config:

Extended Key Usages: 1.3.6.1.5.5.7.3.3 X.509 Key Usage flags: Digital Signature, Key Encipherment Reuse key on renewal: NO Exportable Private Key: NO Key Type: RSA-HSM Key Size: 4096 Enable Cert Transparency: NO

Here is my jarsigner command (note using debug):

/usr/bin/jarsigner \
-J-Djava.security.debug=jar \
-keystore NONE \
-sigalg SHA512withRSA \
-storetype AzureKeyVault \
-signedjar signed.jar $1 "HomeSelfSignedCert3072PKCS" \
-verbose \
-storepass ' ' \
-providerName AzureKeyVault \
-J-cp -J./azure-security-keyvault-jca-2.8.0-beta.1.jar \
-providerClass com.azure.security.keyvault.jca.KeyVaultJcaProvider \
-J'-Dazure.keyvault.uri=https://REDACTED.vault.azure.net/' \
-J'-Dazure.keyvault.tenant-id=REDACTED' \
-J'-Dazure.keyvault.client-id=REDACTED' \
-J'-Dazure.keyvault.client-secret=REDACTED'

Here is the result I was getting before your most recent commit 6bc9de2:

$ ./jcc_sign_it_now.sh unsigned.jar
Sep 12, 2023 6:51:29 AM com.azure.security.keyvault.jca.implementation.KeyVaultClient <init>
INFO: Using Azure Key Vault: https://azpremkv.vault.azure.net/
Sep 12, 2023 6:51:29 AM com.azure.security.keyvault.jca.implementation.utils.AccessTokenUtil getAccessToken
INFO: Getting access token using client ID / client secret
Sep 12, 2023 6:51:31 AM com.azure.security.keyvault.jca.implementation.KeyVaultClient getKey
INFO: Getting key for alias: HomeCert3072PKCS
Sep 12, 2023 6:51:31 AM com.azure.security.keyvault.jca.implementation.KeyVaultClient getCertificate
INFO: Getting certificate for alias: HomeCert3072PKCS
Sep 12, 2023 6:51:31 AM com.azure.security.keyvault.jca.implementation.KeyVaultClient getKey
INFO: Getting key for alias: HomeSelfSignedCert3072PKCS
Sep 12, 2023 6:51:32 AM com.azure.security.keyvault.jca.implementation.KeyVaultClient getCertificate
INFO: Getting certificate for alias: HomeSelfSignedCert3072PKCS
Sep 12, 2023 6:51:32 AM com.azure.security.keyvault.jca.implementation.KeyVaultClient <init>
INFO: Using Azure Key Vault: https://azpremkv.vault.azure.net/
Sep 12, 2023 6:51:32 AM com.azure.security.keyvault.jca.implementation.utils.AccessTokenUtil getAccessToken
INFO: Getting access token using client ID / client secret
Sep 12, 2023 6:51:32 AM com.azure.security.keyvault.jca.implementation.KeyVaultClient getKey
INFO: Getting key for alias: HomeCert3072PKCS
Sep 12, 2023 6:51:33 AM com.azure.security.keyvault.jca.implementation.KeyVaultClient getCertificate
INFO: Getting certificate for alias: HomeCert3072PKCS
Sep 12, 2023 6:51:33 AM com.azure.security.keyvault.jca.implementation.KeyVaultClient getKey
INFO: Getting key for alias: HomeSelfSignedCert3072PKCS
Sep 12, 2023 6:51:34 AM com.azure.security.keyvault.jca.implementation.KeyVaultClient getCertificate
INFO: Getting certificate for alias: HomeSelfSignedCert3072PKCS
 updating: META-INF/MANIFEST.MF
   adding: META-INF/HOMESELF.SF
   adding: META-INF/HOMESELF.RSA
  signing: HelloWorld.class

jar: beginEntry META-INF/MANIFEST.MF
jar: beginEntry META-INF/HOMESELF.SF
jar: processEntry: processing block
jar: beginEntry META-INF/HOMESELF.RSA
jar: processEntry: processing block
jar: processEntry caught: java.security.SignatureException: Signature length not correct: got 8 but was expecting 512
jar: done with meta!
jar: nothing to verify!
>>> Signer
    X.509, CN=KallahanHome
    [trusted certificate]

jar signed.

Warning:
The signer's certificate is self-signed.

Here is the result I am now getting after your most recent commit 6bc9de2:

$ ./jcc_sign_it_now.sh unsigned.jar
Sep 12, 2023 7:47:33 AM com.azure.security.keyvault.jca.implementation.KeyVaultClient <init>
INFO: Using Azure Key Vault: https://azpremkv.vault.azure.net/
Sep 12, 2023 7:47:33 AM com.azure.security.keyvault.jca.implementation.utils.AccessTokenUtil getAccessToken
INFO: Getting access token using client ID / client secret
Sep 12, 2023 7:47:37 AM com.azure.security.keyvault.jca.implementation.KeyVaultClient getKey
INFO: Getting key for alias: HomeCert3072PKCS
Sep 12, 2023 7:47:37 AM com.azure.security.keyvault.jca.implementation.KeyVaultClient getCertificate
INFO: Getting certificate for alias: HomeCert3072PKCS
Sep 12, 2023 7:47:38 AM com.azure.security.keyvault.jca.implementation.KeyVaultClient getKey
INFO: Getting key for alias: HomeSelfSignedCert3072PKCS
Sep 12, 2023 7:47:38 AM com.azure.security.keyvault.jca.implementation.KeyVaultClient getCertificate
INFO: Getting certificate for alias: HomeSelfSignedCert3072PKCS
Sep 12, 2023 7:47:38 AM com.azure.security.keyvault.jca.implementation.KeyVaultClient <init>
INFO: Using Azure Key Vault: https://azpremkv.vault.azure.net/
Sep 12, 2023 7:47:38 AM com.azure.security.keyvault.jca.implementation.utils.AccessTokenUtil getAccessToken
INFO: Getting access token using client ID / client secret
Sep 12, 2023 7:47:39 AM com.azure.security.keyvault.jca.implementation.KeyVaultClient getKey
INFO: Getting key for alias: HomeCert3072PKCS
Sep 12, 2023 7:47:39 AM com.azure.security.keyvault.jca.implementation.KeyVaultClient getCertificate
INFO: Getting certificate for alias: HomeCert3072PKCS
Sep 12, 2023 7:47:40 AM com.azure.security.keyvault.jca.implementation.KeyVaultClient getKey
INFO: Getting key for alias: HomeSelfSignedCert3072PKCS
Sep 12, 2023 7:47:40 AM com.azure.security.keyvault.jca.implementation.KeyVaultClient getCertificate
INFO: Getting certificate for alias: HomeSelfSignedCert3072PKCS
 updating: META-INF/MANIFEST.MF
   adding: META-INF/HOMESELF.SF
   adding: META-INF/HOMESELF.RSA
  signing: HelloWorld.class

jar: beginEntry META-INF/MANIFEST.MF
jar: beginEntry META-INF/HOMESELF.SF
jar: processEntry: processing block
jar: beginEntry META-INF/HOMESELF.RSA
jar: processEntry: processing block
jar: Signature Block Certificate: [
[
  Version: V3
  Subject: CN=KallahanHome
  Signature Algorithm: SHA256withRSA, OID = 1.2.840.113549.1.1.11

  Key:  Sun RSA public key, 4096 bits
  params: null
  modulus: 840838420139145776249025751413243908756506301891843392167435996527433986134554537391373344627556162132329988597681361405483119867161701371292217933003606089696934076553328976139061934109987670737510353076860603634759415798188588319887407095193677150294404744070639231768531594241258194996225820856216424226320274475557307014566807998451421008273557186165958447729313334131751046539974564895987294671649563369584440590961445418456416989881802277797225997279865141037335235614811529171299294304249123261144545672351811214898488859776066783880411485652182479126295505402114824573609608541163570770383791837700005288653079334817188310096865589596667146951135936089936943031469709622897002542908455237838389068203353168314351821270411712832835309715493732239305562439302496095714499330192425656938747760064567258992559562706371029809979566109475725948854376002806908535907638235102764823128597342856801995527019784694581745830505431923049048800631863223192119991616077850590690361681848519141342705179022975857073356001985172757705029703082948400424058673202933064018739192171811091959459626450725962311386630507946265402849902999780218730691172700461060254416357951556775705288281631498111362207775670686639994499510796765980160825571367
  public exponent: 65537
  Validity: [From: Tue Sep 12 06:36:30 CDT 2023,
               To: Thu Sep 12 06:46:30 CDT 2024]
  Issuer: CN=KallahanHome
  SerialNumber: [    5b2c8d37 8fba422c 8ca6b2f8 d4e1c547]

Certificate Extensions: 5
[1]: ObjectId: 2.5.29.35 Criticality=false
AuthorityKeyIdentifier [
KeyIdentifier [
0000: E1 9F 9B E2 58 94 48 39   34 92 B2 AD 4C 9C 5E BC  ....X.H94...L.^.
0010: 26 51 EE FD                                        &Q..
]
]

[2]: ObjectId: 2.5.29.19 Criticality=false
BasicConstraints:[
  CA:false
  PathLen: undefined
]

[3]: ObjectId: 2.5.29.37 Criticality=false
ExtendedKeyUsages [
  codeSigning
]

[4]: ObjectId: 2.5.29.15 Criticality=true
KeyUsage [
  DigitalSignature
  Key_Encipherment
]

[5]: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: E1 9F 9B E2 58 94 48 39   34 92 B2 AD 4C 9C 5E BC  ....X.H94...L.^.
0010: 26 51 EE FD                                        &Q..
]
]

]
  Algorithm: [SHA256withRSA]
  Signature:
0000: 40 0F 64 11 67 FD 37 4B   67 36 A2 D6 5B BE DB 95  @.d.g.7Kg6..[...
0010: 4A C4 6B 08 3D 17 69 7A   B5 78 4D 03 8D E1 1F 00  J.k.=.iz.xM.....
0020: 8E 5F AE E5 50 C5 8B 05   85 46 62 B1 83 93 76 04  ._..P....Fb...v.
0030: 4C 43 08 A8 F9 49 D4 CD   34 57 D3 DF 90 07 3F 82  LC...I..4W....?.
0040: 26 7C 2F 10 5C 29 EF 4F   19 21 EC 0F B5 8C 2B F9  &./.\).O.!....+.
0050: 8A D5 82 BC 13 A4 D4 27   6D 5D 38 9F BA E3 3D 9A  .......'m]8...=.
0060: DA EE 58 64 CC B3 3B 18   61 07 4A 86 AC E3 2C 7C  ..Xd..;.a.J...,.
0070: FB 63 C2 BD 98 E1 B0 FF   60 0C 40 1B 8C 44 0A A1  .c......`.@..D..
0080: FF 9D 92 0A A4 57 39 57   FA EC 7F 02 A7 73 F6 D2  .....W9W.....s..
0090: 18 B6 7D FF BC 9E C8 DB   0F 2D 33 94 D4 DC 20 1E  .........-3... .
00A0: 22 FB E1 44 D7 49 70 48   14 F0 B0 5B 23 0C 2B 66  "..D.IpH...[#.+f
00B0: 86 4F 3F E1 90 E4 5B C1   3E BE 58 75 40 7D 31 A3  .O?...[.>.Xu@.1.
00C0: F6 BD AD C8 DB 09 F4 55   80 D7 C6 0A 14 36 1A A5  .......U.....6..
00D0: 6B F8 28 AD 08 81 DA C8   00 59 36 F7 A4 7D 5F 76  k.(......Y6..._v
00E0: C8 96 0F 1A 55 81 7D 47   61 5F 32 E0 00 AB 32 A0  ....U..Ga_2...2.
00F0: 08 7C 21 DD CE 16 F0 E8   58 E9 61 9C F9 B2 55 D6  ..!.....X.a...U.
0100: F4 6B 77 B4 FE 87 54 7B   EB 14 22 E7 DE A8 32 59  .kw...T..."...2Y
0110: D9 35 14 39 12 6F 01 1A   CA 86 3D A6 A2 53 99 E9  .5.9.o....=..S..
0120: A8 09 EF A3 A9 DD 1B B9   0C A3 34 24 6B 1B 85 BA  ..........4$k...
0130: A1 42 F7 5D E2 CD 44 58   EF 2F B5 9D FC C5 B5 0A  .B.]..DX./......
0140: FE 38 BC FA 00 A2 9B BB   0A 8A 65 2F F1 42 0F C8  .8........e/.B..
0150: 58 58 55 B8 73 AC B6 77   23 82 80 D1 B4 D4 15 1F  XXU.s..w#.......
0160: 25 B6 06 C7 93 E0 39 CB   E9 B6 34 90 85 21 12 78  %.....9...4..!.x
0170: 48 A2 24 6F 8F 5A A0 BF   66 7C BA E2 F9 ED 23 3A  H.$o.Z..f.....#:
0180: 4E BB 5A 71 5D 6F 8B 0D   27 A1 74 EF E3 32 3D E2  N.Zq]o..'.t..2=.
0190: A5 86 92 22 DD 9B 0F A1   92 5C 5F D2 63 80 82 94  ...".....\_.c...
01A0: 66 C1 8C 15 75 65 62 B6   FF 39 8C 35 BB 32 F4 EB  f...ueb..9.5.2..
01B0: 07 B4 17 3C 94 E8 DE 46   D8 B8 6A 77 53 4E 7E 90  ...<...F..jwSN..
01C0: 8C DB 0D 42 B7 6E 26 83   B8 A3 B2 44 FB 0C 11 18  ...B.n&....D....
01D0: 4C BA 69 9F 8C 95 94 D8   11 1C 13 C5 ED 02 61 4A  L.i...........aJ
01E0: 0F 71 9F 04 41 DD E1 C6   32 3C 4B 92 95 4C 70 94  .q..A...2<K..Lp.
01F0: EA 3E 3E 2D B1 5A EC B1   EA 04 7A 2F FC 45 3F F3  .>>-.Z....z/.E?.

]
jar: Signature File: Manifest digest SHA-256
jar:   sigfile  6c50256d1ce5cca5d53c7b3d0bac0adc86a76b97d3b20fefc4a1e17b88da3c19
jar:   computed 6c50256d1ce5cca5d53c7b3d0bac0adc86a76b97d3b20fefc4a1e17b88da3c19
jar:
jar: PermittedAlgs mapping:
jar: SHA512withRSA : true
jar: SHA-256 : true
jar: SHA-512 : true
jar: processSignature signed name = HelloWorld.class
jar: done with meta!
jar: beginEntry META-INF/HOMESELF.RSA
>>> Signer
    X.509, CN=KallahanHome
    [trusted certificate]

jar signed.

Warning:
The signer's certificate is self-signed.
saragluna commented 1 year ago

Thanks @hounster for the update.

malmor commented 1 year ago

Hey @saragluna, thanks for the updated repository.

I just gave it another try - and now jarsigner is able to verify the signature:

PS C:\test> jarsigner -verify -debug -verbose -certs -J'-Djava.security.debug=jar' signed-jar.jar

  s = signature was verified
  m = entry is listed in manifest
  k = at least one certificate was found in keystore

- Signed by "CN=Company, OU=Company, O=Company, L=City, C=Country"
    Digest algorithm: SHA-384
    Signature algorithm: SHA512withRSA, 3072-bit key

jar verified.

Warning:
This jar contains entries whose certificate chain is invalid. Reason: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

This jar contains signatures that do not include a timestamp. Without a timestamp, users may not be able to validate this jar after any of the signer certificates expire (as early as 2025-06-12).
POSIX file permission and/or symlink attributes detected. These attributes are ignored when signing and are not protected by the signature.

The signer certificate will expire on 2025-06-12.

But it throws another issue:

sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target 
        at java.base/sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:388)
        at java.base/sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:271)
        at java.base/sun.security.validator.Validator.validate(Validator.java:256)
        at java.base/sun.security.validator.Validator.validate(Validator.java:223)
        at jdk.jartool/sun.security.tools.jarsigner.Main.validateCertChain(Main.java:2521)
        at jdk.jartool/sun.security.tools.jarsigner.Main.certsAndTSInfo(Main.java:2160)
        at jdk.jartool/sun.security.tools.jarsigner.Main.signerInfo(Main.java:2116)
        at jdk.jartool/sun.security.tools.jarsigner.Main.verifyJar(Main.java:888)
        at jdk.jartool/sun.security.tools.jarsigner.Main.run(Main.java:303)
        at jdk.jartool/sun.security.tools.jarsigner.Main.main(Main.java:138)
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
        at java.base/sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141)
        at java.base/sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126)
        at java.base/java.security.cert.CertPathBuilder.build(CertPathBuilder.java:297)
        at java.base/sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:383)
        ... 9 more
s       4748 Wed Sep 13 08:13:42 GMT+02:00 2023 META-INF/MANIFEST.MF

I am not sure if that is an issue with our certificate, our setup or something else.

saragluna commented 1 year ago

I am not sure whether this exception is because the certificate is a self-signed certificate.

malmor commented 1 year ago

Hey @saragluna, we are not using a self-signed certificate - it is an official certificate bought from DigiCert.

hounster commented 1 year ago

@malmor - You can fix the missing timestamp issue by adding this option to your jarsigner command:

-tsa 'http://timestamp.digicert.com'

As to the issue of "certificate chain invalid", don't quote me on this but I believe jarsigner always expects the full certificate chain to be available. Seeing this makes me think that when you followed the steps to "merge" and complete your certificate in Azure Keyvault, that you merged the public certificate only, as opposed to merging a .p7b file containing all of the certificates. One way to confirm is concatenate all of the certificates into a text file, in the proper order, have it locally available on your workstation, and point to it by adding this option to jarsigner:

-certchain INSERT_NAME_OF_FILE_HERE

hounster commented 1 year ago

@malmor Just to clarify in case not clear - when I referred to "all of the certificates", I simply meant all of the public certificates that make up the full chain:

Add them into your "chain file", in that order.

jyuenatsolarsoft commented 1 year ago

@saragluna @backwind1233

Thanks so much for the latest changes.

The build compiled from the test repo seems to be working okay to me now. I am able to properly sign my jar files and validate them. Do we have any idea when this fix will be officially released in a new version of the JCA provider?

We're trying to understand if this beta version is stable enough for the production environment or it's better to wait for the official version, if it's not too far away from being released. Thanks.

malmor commented 1 year ago

@hounster thanks for the information!

We are already using timestamps when signing our releases - must have missed it when testing the beta version locally. I will play around with the "full chain" issue - if your hint goes in the right direction, then this should be quite easy to test and fix šŸ‘

saragluna commented 1 year ago

Hi @jyuenatsolarsoft, if everything goes well, we could release a new version by the end of this month.

schannaveera1 commented 1 year ago

Hi,

is everything working as expected, I am able to sign but not verify and while signing I see this issue "**jar: processEntry caught: java.security.SignatureException: ".

jar: processEntry: processing block jar: Unsupported signer attribute: 1.2.840.113549.1.9.16.2.47 jar: jar: Detected signature timestamp (#67777975150123403729185685483830998061) generated on Mon Oct 02 09:31:01 CDT 2023 jar: jar: processEntry caught: java.security.SignatureException: Signature length not correct: got 0 but was expecting 512 jar: done with meta! jar: nothing to verify! jar: Unsupported signer attribute: 1.2.840.113549.1.9.16.2.47 jar: Unsupported signer attribute: 1.2.840.113549.1.9.16.2.47

Do you guys have any inputs?

schannaveera1 commented 1 year ago

@backwind1233 any assistance?

saragluna commented 1 year ago

@schannaveera1 could you provide the certificate advanced policy configuration?

schannaveera1 commented 1 year ago

@saragluna, The parameters are as below.

Extended Key Usages : 1.3.6.1.5.5.7.3.1, 1.3.6.1.5.5.7.3.2,1.3.6.1.5.5.7.3.3 X.509 key Usage Flags: Digital signature, key encipherment Resurge key on renewal: No Exportable Private Key : No Key Type: RSA HSM Key Size : 4096 Enable certificate Transparency : Yes

brianandle commented 1 year ago

FYI. I was getting the same error described, private key is not a DSA or RSA key, in this thread using AzureKeyVault with Entrust. I'm able to confirm that the fork here https://github.com/saragluna/azure-security-kv-jca-fork doesn't throw the error and does result in a successful signing.

We're working through the "PKIX path building failed" issue now, which I believe is due to us missing intermediate certs defined in the AzureKeyVault (or it could be an issue in the KeyVaultJcaProvider).

We're moving from Sectigo SafeNet HSM to Azure Key Vault and when we had this issue with it was because we didn't have the intermediates installed in the HSM so Java didn't know how to find/include the intermediates as part of the signed.

Update: We checked and the full chain is in fact already in the KeyVault, but we do get the PKIX path error. If I take the same chain and pass it in using the -certchain option then it works as expected. So I suspect that the KeyVaultProvider isn't making the chain available... maybe

saragluna commented 1 year ago

@brianandle the fix from the fork repo has already been merged, and we will look into the cert chain issue now. But have you tried this https://github.com/Azure/azure-sdk-for-java/issues/35677#issuecomment-1717593203?

saragluna commented 1 year ago

Hi,

is everything working as expected, I am able to sign but not verify and while signing I see this issue "**jar: processEntry caught: java.security.SignatureException: ".

jar: processEntry: processing block jar: Unsupported signer attribute: 1.2.840.113549.1.9.16.2.47 jar: jar: Detected signature timestamp (#67777975150123403729185685483830998061) generated on Mon Oct 02 09:31:01 CDT 2023 jar: jar: processEntry caught: java.security.SignatureException: Signature length not correct: got 0 but was expecting 512 jar: done with meta! jar: nothing to verify! jar: Unsupported signer attribute: 1.2.840.113549.1.9.16.2.47 jar: Unsupported signer attribute: 1.2.840.113549.1.9.16.2.47

Do you guys have any inputs?

@schannaveera1 seems like it's not signed correctly in your case?

schannaveera1 commented 1 year ago

@saragluna, In my case I get the error with the message "jar: Unsupported signer attribute: 1.2.840.113549.1.9.16.2.47 jar: jar: Detected signature timestamp (#67777975150123403729185685483830998061) generated on Mon Oct 02 09:31:01 CDT 2023 jar: jar: processEntry caught: java.security.SignatureException: Signature length not correct: got 0 but was expecting 512 jar: done with meta! jar: nothing to verify! jar: Unsupported signer attribute: 1.2.840.113549.1.9.16.2.47 jar: Unsupported signer attribute: 1.2.840.113549.1.9.16.2.47

And Jar signed.

For Verify,

WARNING: Signature is either not parsable or not verifiable, and the jar will be treated as unsigned. For more information, re-run jarsigner with debug enabled (-J-Djava.security.debug=jar).

brianandle commented 1 year ago

35677 (comment)

We verified that the full chain exists in the AKV/HSM for the cert, however we still had to define the -certchain=local_cert_chain.pem which we didn't have to do with Sectigo. So we have a workaround but ideally we wouldn't need to have to define the -certchain at all as we didn't need yo do that with another vendor.

schannaveera1 commented 11 months ago

@saragluna do you need any additional information from to help us resolve.

saragluna commented 11 months ago

@schannaveera1, yes, we can't reproduce this error. Could you help provide more information?

malmor commented 11 months ago

Hey everyone, I just wanted to give you a quick update from my side.

@malmor - You can fix the missing timestamp issue by adding this option to your jarsigner command: -tsa 'http://timestamp.digicert.com'

As to the issue of "certificate chain invalid", don't quote me on this but I believe jarsigner always expects the full certificate chain to be available. Seeing this makes me think that when you followed the steps to "merge" and complete your certificate in Azure Keyvault, that you merged the public certificate only, as opposed to merging a .p7b file containing all of the certificates. One way to confirm is concatenate all of the certificates into a text file, in the proper order, have it locally available on your workstation, and point to it by adding this option to jarsigner: -certchain INSERT_NAME_OF_FILE_HERE

Thanks a lot @hounster for your tips regarding the jarsigner warnings. I enabled timestamping and provided the combined list of public keys as a chain.p7b file - and now jarsigner successfully signs and verifies jars with our certificate stored in a HSM azure key vault šŸ„³

We are now using the latest version v2.8.0 of the azure-security-keyvault-jca jar that contains the support for HSM secrets (FYI @jyuenatsolarsoft).

Here is the command that we are using (windows powershell):

# Sign the jar
# - '-certchain' is required because our certificate in azure is missing the official public certificates in the chain
# - secrets are provided by environment variables
# - we had to hardcode the path to the azure-security-keyvault-jca jar because of some internal limitation
jarsigner ^
-verbose ^
-certchain chain.p7b ^
-keystore NONE ^
-storetype AzureKeyVault ^
-storepass ' ' ^
-tsa http://timestamp.digicert.com ^
target\azure-sdk-for-java-signing-example-1.0.0.jar ^
"$env:AZURE_KEY_VAULT_CERT_NAME" ^
-providerName AzureKeyVault ^
-providerPath C:\repository\com\azure\azure-security-keyvault-jca\2.8.0\azure-security-keyvault-jca-2.8.0.jar ^
-providerClass com.azure.security.keyvault.jca.KeyVaultJcaProvider ^
-J"-Dazure.keyvault.uri=$env:AZURE_KEY_VAULT_URL" ^
-J"-Dazure.keyvault.tenant-id=$env:AZURE_KEY_VAULT_TENANT_ID" ^
-J"-Dazure.keyvault.client-id=$env:AZURE_KEY_VAULT_CLIENT_ID" ^
-J"-Dazure.keyvault.client-secret=$env:AZURE_KEY_VAULT_CLIENT_SECRET"

# Verify the jar
jarsigner -verify -debug -verbose -certs target\azure-sdk-for-java-signing-example-1.0.0.jar`

Thanks a lot @backwind1233 and @saragluna for your support on this issue. šŸ™Œ

As far as I am concerned this issue is resolved. But because of the latest questions I will leave it up to you to close this - feel free to keep the conversation going or to move it to a different issue šŸ˜ƒ

Regards, Malte

schannaveera1 commented 11 months ago

Hi @saragluna,

I am attaching logs here, there is new error with "azure-security-keyvault-jca-2.8.0.jar. I am not at all able to sign now. Attached are the logs. Any help

The command I am using to sign

"C:\Program Files\Java\jdk-19\bin\jarsigner.exe" -verbose -debug -keystore NONE ^ -sigalg RSASSA-PSS -storetype AzureKeyVault -tsa http://timestamp.digicert.com ^ -storepass " " ^ -providerPath "C:\codesign\jarsign\azure-security-keyvault-jca-2.8.0.jar" ^ -providerName AzureKeyVault -providerClass com.azure.security.keyvault.jca.KeyVaultJcaProvider -J-Dazure.keyvault.uri=https://sapguixrx.vault.azure.net/ ^ -J-Dazure.keyvault.client-secret=########^ -J-Dazure.keyvault.client-id=############# ^ -J-Dazure.keyvault.tenant-id=############ ^ -certchain C:\codesign\jarsign\sap.p7b "C:\codesign\jarsign\sample.jar" sapguixrx

"java.lang.SecurityException: invalid SHA-256 signature file digest for com/azure/security/keyvault/jca/implementation/shaded/com/fasterxml/jackson/annotation/JsonProperty$Access.class at java.base/sun.security.util.SignatureFileVerifier.verifySection(SignatureFileVerifier.java:692) at java.base/sun.security.util.SignatureFileVerifier.processImpl(SignatureFileVerifier.java:351) at java.base/sun.security.util.SignatureFileVerifier.process(SignatureFileVerifier.java:282) at java.base/java.util.jar.JarVerifier.processEntry(JarVerifier.java:327) at java.base/java.util.jar.JarVerifier.update(JarVerifier.java:239) at java.base/java.util.jar.JarFile.initializeVerifier(JarFile.java:760) at java.base/java.util.jar.JarFile.getInputStream(JarFile.java:846) at jdk.jartool/sun.security.tools.jarsigner.Main.signJar(Main.java:2032) at jdk.jartool/sun.security.tools.jarsigner.Main.run(Main.java:308) at jdk.jartool/sun.security.tools.jarsigner.Main.main(Main.java:138) jar signed."

jar sign logs.txt cert-param

saragluna commented 11 months ago

@schannaveera1 sorry for the late reply, but on our end we can't reproduce your error. But could you help generate a self-signed certificate in kv, and test whether the library can use that cert to sign the jar? If so, we could narrow the issue to something special in your cert.

karla-barraza commented 7 months ago

Did this fix ultimately get merged?

malmor commented 7 months ago

@karla-barraza are you referring to the jarsigner support (the initial issue described above)? Then yes, it should be available for all versions starting with v2.8.0 of the azure-security-keyvault-jca package.