Cómo firmar un archivo .jar utilizando el esquema de firma XMSS (PQC) con JarSigner

1

Estoy tratando de usar JarSigner para firmar archivos .jar con firmas XMSS . Con el uso de JCA / JCE Criptografía post-cuántica Provider de BouncyCastle es posible generar el programa XMSS y XMSSMT KeyPairs programáticamente (ejemplo) . Para usar JarSigner es, por lo que sé, crucial proporcionar un KeyStore y el alias de la entrada con el que uno quiere firmar su código con: jarsigner -keystore myKeystore -storetype JKS -storepass password -keypass password myjarfile.jar keystoreEntryAlias La entrada KeyStore contiene el KeyPair Público / Secreto y la X asociada. Certificado 509.

La forma "normal" de firmar un archivo Jar con JarSigner es la siguiente:

  1. Use keytool para generar el par de claves público / secreto y un certificado, luego guárdelos en un KeyStore ( keytool -genkeypair -alias keystoreEntryAlias -keyalg RSA -sigalg SHA256withRSA -dname CN=MyCompanyName -storetype JKS -keypass password -keystore mykeystore.jks -storepass password )
  2. Use JarSigner para firmar el .jar usando la clave secreta almacenada en mykeystore.jks con el alias keysotreEntryAlias ( jarsigner -keystore mykeystore.jks -storetype jks -storepass passeword -keypass password myjarfile.jar keystoreEntryAlias )

Para firmar mi archivo con una clave XMSS teóricamente tengo dos posibilidades:

  1. Use BCPQC para crear XMSS KeyPairs programáticamente, guárdelos en mykeystore y use jarsigner -keystore mykeystore -alias xmss a través de CLI para firmar mi archivo.
  2. Use BCPQC-Provider con keytool para generar directamente a través de CLI XMSS KeyPairs y almacenarlos en mykeystore (keytool aquí necesitaría 2 argumentos más: -providerclass org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider y -providerpath C:\Path\to\BouncyCastle\provider\bcprov-jdk15on-160.jar ) Luego firme el archivo con la entrada del keystore usando JarSigner

Lamentablemente me encuentro con problemas con ambas posibilidades:

  1. Como todavía no he encontrado una manera de usar JarSigner sin CLI, debo colocar mis KeyPairs XMSS generados en un KeyStore, pero para eso necesito el certificado que incluye la clave pública XMSS. BouncyCastle proporciona un X.509CertificateBuilder que se puede usar para generar el certificado necesario, sin embargo, algo parece ir mal si observa el certificado generado, especialmente el algoritmo de firma y la clave pública (código fuente en la parte inferior [CertificateBuilderExample], usando XMSSMT)
  2. Parece que keytool solo usa la sobrecarga de inicio (int) de BCPQCProvider y XMSSKeyPairGeneratorSpi rechaza eso; quiere AlgorithmParameterSpec específicamente XMSSParameterSpec, o no init en absoluto, y si intento esto último, genera un par de claves, pero las claves resultantes no se pueden codificar y, por lo tanto, no se pueden almacenar en KeyStore.

Mi pregunta ahora sería:

¿Alguien sabe de una manera de firmar archivos .jar usando XMSS / XMSSMT con JarSigner y puede proporcionar una explicación más o menos detallada de lo que hizo bien y de lo que hice mal? ¿O si me equivoqué con respecto a algo que mencioné anteriormente, ofrezco una corrección y señale una forma de hacerlo?

ACTUALIZACIÓN 1 : ahora soy capaz, con el uso de otro X509CertificateGenerator (código fuente en la parte inferior [X509CertificateGenerator]) e información recopilada de here , here y here , para firmar archivos jar programáticamente con RSA proporcionado de BouncyCastle (Código fuente para firmar en la parte inferior [RSA_JarSigner]).

Si trato de aplicar el mismo esquema utilizado para firmar con RSA para firmar con XMSS o XMSSMT, me encuentro con un JarSignerException: Error in signer materials causado por NoSuchAlgorithmException: unrecognized algorithm name: XMSS (Código fuente de XMSS / XMSSMT en la parte inferior [SignXMSS] [SignXMSSMT]).

¡Espero que alguien pueda ayudarme a averiguar dónde está el problema!

[CertificateBuilderExample]

import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.BasicConstraints;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.KeyUsage;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider;
import org.bouncycastle.pqc.jcajce.spec.XMSSMTParameterSpec;

import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.security.*;
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.Random;


public class App {

    public static void main(String[] args) throws Exception {
        Security.addProvider(new BouncyCastlePQCProvider());

        SimpleDateFormat sdf = new SimpleDateFormat("dd-M-yyyy hh:mm:ss");
        String datefrom = "12-08-2018 10:20:56";
        String dateuntil = "12-05-2020 10:20:56";
        Date from = sdf.parse(datefrom);
        Date until = sdf.parse(dateuntil);

        // Create self signed Root CA certificate
        KeyPair rootCAKeyPair = generateKeyPair();
        X509v3CertificateBuilder builder = new JcaX509v3CertificateBuilder(
                new X500Name("CN=rootCA"), // issuer authority
                BigInteger.valueOf(new Random().nextInt()), //serial number of certificate
                from, // start of validity
                until, //end of certificate validity
                new X500Name("CN=rootCA"), // subject name of certificate
                rootCAKeyPair.getPublic()); // public key of certificate
        // key usage restrictions
        builder.addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.keyCertSign));
        builder.addExtension(Extension.basicConstraints, false, new BasicConstraints(true));
        X509Certificate rootCA = new JcaX509CertificateConverter().getCertificate(builder
                .build(new JcaContentSignerBuilder("SHA256withXMSSMT").setProvider("BCPQC").
                        build(rootCAKeyPair.getPrivate()))); // private key of signing authority , here it is self signed
        saveToFile(rootCA, "rootCA.cer");

    }

    private static KeyPair generateKeyPair() throws NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException {
        KeyPairGenerator kpGen = KeyPairGenerator.getInstance("XMSSMT", "BCPQC");
        kpGen.initialize(new XMSSMTParameterSpec(20, 10, XMSSMTParameterSpec.SHA256), new SecureRandom());
        KeyPair kp = kpGen.generateKeyPair();
        System.out.print("Public key:" + Arrays.toString(kp.getPublic().getEncoded()));
        return kp;
    }

    private static void saveToFile(X509Certificate certificate, String filePath) throws IOException, CertificateEncodingException {
        FileOutputStream fileOutputStream = new FileOutputStream(filePath);
        fileOutputStream.write(certificate.getEncoded());
        fileOutputStream.flush();
        fileOutputStream.close();
    }

}

[X509CertificateGenerator]

public X509Certificate generateCertificate(String dn, KeyPair keyPair, int validity, String sigAlgName) throws GeneralSecurityException, IOException {
        PrivateKey privateKey = keyPair.getPrivate();

        X509CertInfo info = new X509CertInfo();

        Date from = new Date();
        Date to = new Date(from.getTime() + validity * 1000L * 24L * 60L * 60L);

        CertificateValidity interval = new CertificateValidity(from, to);
        BigInteger serialNumber = new BigInteger(64, new SecureRandom());
        X500Name owner = new X500Name(dn);
        AlgorithmId sigAlgId = new AlgorithmId(AlgorithmId.md5WithRSAEncryption_oid);

        info.set(X509CertInfo.VALIDITY, interval);
        info.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber(serialNumber));
        info.set(X509CertInfo.SUBJECT, owner);
        info.set(X509CertInfo.ISSUER, owner);
        info.set(X509CertInfo.KEY, new CertificateX509Key(keyPair.getPublic()));
        info.set(X509CertInfo.VERSION, new CertificateVersion(CertificateVersion.V3));
        info.set(X509CertInfo.ALGORITHM_ID, new CertificateAlgorithmId(sigAlgId));

        // Sign the cert to identify the algorithm that's used.
        X509CertImpl certificate = new X509CertImpl(info);
        certificate.sign(privateKey, sigAlgName);

        // Update the algorith, and resign.
        sigAlgId = (AlgorithmId) certificate.get(X509CertImpl.SIG_ALG);
        info.set(CertificateAlgorithmId.NAME + "." + CertificateAlgorithmId.ALGORITHM, sigAlgId);
        certificate = new X509CertImpl(info);
        certificate.sign(privateKey, sigAlgName);

        return certificate;
    }

[RSA_JarSigner]

public class JarSignerTest {

    public static void main(String[] args) throws Exception{
        JarSignerTest jst = new JarSignerTest();
        jst.SignRSA();
    }

    public void SignRSA() throws Exception{
        Security.addProvider(new BouncyCastleProvider());
        File inputFile = new File("C:\Path\to\jar\toSign\jarfile.jar"),
                outputfile = new File("C:\Path\to\signedJar\jarfile.jar");
        X509CertificateGen x509certgen = new X509CertificateGen();
        KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", "BC");
        kpGen.initialize(1024, new SecureRandom());
        KeyPair keyPair = kpGen.generateKeyPair();
        Certificate[] chain = {x509certgen.generateCertificate("cn=Unknown", keyPair, 356, "SHA256withRSA")};
        List<? extends Certificate> foo = Arrays.asList(chain);
        CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
        CertPath certPath = certificateFactory.generateCertPath(foo);
        JarSigner signer = new JarSigner.Builder(keyPair.getPrivate(), certPath)
                .digestAlgorithm("SHA-256")
                .signatureAlgorithm("SHA256withRSA")
                .build();
        try (ZipFile in = new ZipFile(inputFile);
             FileOutputStream out = new FileOutputStream(outputfile)){
            signer.sign(in, out);
        }
    }
}

[SignXMSS]

public void SignXMSS() throws Exception{
    Security.addProvider(new BouncyCastlePQCProvider());
    File inputFile = new File("C:\Path\to\jar\toSign\jarfile.jar"),
            outputfile = new File("C:\Path\to\signedJar\jarfile.jar");
    X509CertificateGen x509certgen = new X509CertificateGen();
    KeyPairGenerator kpGen = KeyPairGenerator.getInstance("XMSS", "BCPQC");
    kpGen.initialize(new XMSSParameterSpec(10, XMSSParameterSpec.SHA256), new SecureRandom());
    KeyPair keyPair = kpGen.generateKeyPair();
    Certificate[] chain = {x509certgen.generateCertificate("cn=Unknown", keyPair, 356, "SHA256withXMSS")};
    List<? extends Certificate> foo = Arrays.asList(chain);
    CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
    CertPath certPath = certificateFactory.generateCertPath(foo);
    JarSigner signer = new JarSigner.Builder(keyPair.getPrivate(), certPath)
            .digestAlgorithm("SHA-256")
            .signatureAlgorithm("SHA256withXMSS", new BouncyCastlePQCProvider())
            .build();
    try (ZipFile in = new ZipFile(inputFile);
         FileOutputStream out = new FileOutputStream(outputfile)){
        signer.sign(in, out);
    }
}

[SignXMSSMT]

public void SignXMSSMT() throws Exception{
    Security.addProvider(new BouncyCastlePQCProvider());
    File inputFile = new File("C:\Path\to\jar\toSign\jarfile.jar"),
            outputfile = new File("C:\Path\to\signedJar\jarfile.jar");
    X509CertificateGen x509certgen = new X509CertificateGen();
    KeyPairGenerator kpGen = KeyPairGenerator.getInstance("XMSSMT", "BCPQC");
    kpGen.initialize(new XMSSMTParameterSpec(20, 10, XMSSMTParameterSpec.SHA256), new SecureRandom());
    KeyPair keyPair = kpGen.generateKeyPair();
    Certificate[] chain = {x509certgen.generateCertificate("cn=Unknown", keyPair, 356, "SHA256withXMSSMT")};
    List<? extends Certificate> foo = Arrays.asList(chain);
    CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
    CertPath certPath = certificateFactory.generateCertPath(foo);
    JarSigner signer = new JarSigner.Builder(keyPair.getPrivate(), certPath)
            .digestAlgorithm("SHA-256")
            .signatureAlgorithm("SHA256withXMSSMT")
            .build();
    try (ZipFile in = new ZipFile(inputFile);
         FileOutputStream out = new FileOutputStream(outputfile)){
        signer.sign(in, out);
    }
}
    
pregunta Nicolas Brauer 27.11.2018 - 15:51
fuente

0 respuestas