Usando o JarSigner com RSASSA-PSS

Oct 02 2020

Estou tentando assinar com RSA-PSS um arquivo JAR com o JarSigner usando PKCS # 11. Para especificar o algoritmo de assinatura, o JarSigner usa o sinalizador sigalg . O JDK 14 Docs do JarSigner não especifica quais sigalgs são explicitamente suportados. Testei se o JarSigner aceita "RSASSA-PSS" como um algoritmo válido. O JarSigner não aceita "SHA256withRSASSA-PSS" ou variantes semelhantes de RSASSA-PSS que os Java Crypto Service Providers, como o SunPKCS11 Crypto Service Provider, freqüentemente suportam. Ao tentar assinar com o sigalg "RSASSA-PSS" o JarSigner retorna

jarsigner: unable to sign jar: java.security.SignatureException: Parameters required for RSASSA-PSS signature

Essa exceção significa que os parâmetros PSS não estão definidos. Rastreei o problema até o JarSigner

  • não ter nenhuma maneira de passar os parâmetros PSS através da linha de comando (ver JDK 14 Docs of the JarSigner )
  • nunca definindo parâmetros PSS - o JarSigner.java nunca diretamente (consulte a linha 831 a 843) ou indiretamente (consulte Signature.java e P11PSSSignature.java ) chama setParameter-> setEngineParameter-> setSigParams, que é responsável por definir os parâmetros PSS necessários.

Estou esquecendo de algo? Em caso afirmativo, como posso assinar um arquivo JAR pelo RSA-PSS? Se não, isso é um bug? Afinal, o JarSigner aceita claramente RSASSA-PSS como um sigalg válido. Ou isso é antes uma incompatibilidade entre o JarSigner e a implementação SunPKCS11? Afinal, SunPKCS11 poderia apenas usar valores de parâmetros PSS codificados permanentemente nesse caso.

Respostas

3 kriegaex Oct 06 2020 at 08:47

Parece que ainda não há suporte para isso. Posso reproduzir esse comportamento com a jarsignerferramenta de linha de comando e com o código Java assim:

import jdk.security.jarsigner.JarSigner;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.*;
import java.security.cert.CertPath;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.util.Arrays;
import java.util.zip.ZipFile;

class JarSignerDemo {
  public static void main(String[] args) throws IOException, CertificateException, NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException {
    char[] password = "changeit".toCharArray();
    KeyStore keyStore = KeyStore.getInstance(new File("keystore.jks"), password);
    PrivateKey privateKey = (PrivateKey) keyStore.getKey("mykey", password);
    CertPath certPath = CertificateFactory.getInstance("X.509").generateCertPath(Arrays.asList(keyStore.getCertificateChain("mykey")));
    JarSigner jarSigner = new JarSigner.Builder(privateKey, certPath)
      .digestAlgorithm("SHA-256")
      .signatureAlgorithm("RSASSA-PSS")
      .build();
    try (
      ZipFile jarFile = new ZipFile("my.jar");
      FileOutputStream signedJarFile = new FileOutputStream("my-signed.jar")
    )
    {
      jarSigner.sign(jarFile, signedJarFile);
    }
  }
}
Exception in thread "main" jdk.security.jarsigner.JarSignerException: Error creating signature
    at jdk.jartool/jdk.security.jarsigner.JarSigner.sign(JarSigner.java:573)
    at JarSignerDemo.main(scratch_3.java:28)
Caused by: java.security.SignatureException: Parameters required for RSASSA-PSS signatures
    at java.base/sun.security.rsa.RSAPSSSignature.ensureInit(RSAPSSSignature.java:295)
    at java.base/sun.security.rsa.RSAPSSSignature.engineUpdate(RSAPSSSignature.java:346)
    at java.base/java.security.Signature$Delegate.engineUpdate(Signature.java:1393)
    at java.base/java.security.Signature.update(Signature.java:902)
    at java.base/java.security.Signature.update(Signature.java:871)
    at jdk.jartool/jdk.security.jarsigner.JarSigner.sign0(JarSigner.java:841)
    at jdk.jartool/jdk.security.jarsigner.JarSigner.sign(JarSigner.java:562)
    ... 1 more

Parece que o JDK-8245274 foi criado para adicionar esse recurso ao Java 16. Não tenho 100% de certeza, mas parece que é o seu problema. Você pode querer assistir.


Atualização: um pouco fora do tópico, mas parece que você pode assinar com RSASSA-PSS usando BouncyCastle. Não tenho certeza se isso é uma alternativa para você, no entanto. Talvez você apenas queira alternar para outro tipo de chave.