Is it possible to create a certificate in PFX format and set an OID for some parameters?

Asked

Viewed 1,756 times

6

I need to generate a certificate to simulate an e-CPF. I am creating an implementation to query and validate the digital certificate information e-CPF and e-CNPJ with my application.

The extraction part I already have ready but I don’t have a digital certificate e-CPF to test.

I was able to create the certificate in PFX format with the Java Keytool, but I cannot specify any Object Identifier (OID) for the certificate during creation.

Need to specify 2 Oids, one will contain a string with CPF and the other OID will contain the name of the certificate holder. This is information that comes by default in the e-CPF and e-CNPJ digital certificate.

Consulting this layout I was able to find the corresponding Oids for e-CPF.

It’s them:

  • 2.16.76.1.3.2 = To the responsible
  • 2.16.76.1.3.1 = Contains a number of information such as date of birth of the natural person holding the certificate, CPF and other information

What would be relevant from this field for me would be the CPF, I have already prepared the extraction of this information, I just need to be able to generate the certificate with the e-CPF.

And the command I’m using to generate PFX is this:

keytool -genkeypair -keystore meuCertificado.pfx -storetype PKCS12 -storepass 123456 -alias CERTIFICADO_PARA_TESTES -keyalg RSA -keysize 2048 -validity 99999 -dname "CN=Meu Cert Teste, OU=TESTE, OU=Certificado PF A1, O=MinhaEmpresa, L=MinhaCidade, ST=Minas Gerais, C=SA" -ext san=dns:mydomain.com,dns:localhost,ip:127.0.0.1

Can someone help me?

1 answer

7


For starters, some details:

THE OID 2.16.76.1.3.1 does not only contain the CPF, but a series of information that must be in the correct format for the certificate data to be read correctly. The very document you quoted says the following:

In the first 8 (eight) positions, the date of birth of the natural person holding the certificate, in the format ddmmaaaa; in the 11 (eleven) subsequent positions, the number of registration in the Register of Physical Person (CPF) of the natural person holding the certificate; in the 11 (eleven) subsequent positions, the Social Identification number of the natural person holding the certificate - NIS (PIS, PASEP or CI); in the 15 (fifteen) subsequent positions, the General Registry number - RG of the natural person holding the certificate; in the 6 (six) subsequent positions, the acronyms of the sending agency of the RG and its UF.

Remembering that voter registration and ID are optional, following these rules (also explained in the same document):

When NIS (PIS/PASEP/CI) RG, IEC, or Voter Registration numbers are not available, the corresponding fields must be completed in full with "zero" characters.

If the RG number or the registration number of the Voter Registration Title is not available, do not fill in the fields of shipping agency and UF or the fields Electoral Zone, Session, Municipality and UF, respectively.

All information of variable size, referring to numbers, such as RG, must be filled with "zero" characters on the left to complete its maximum size possible.

The 6 (six) positions of the RG and UF consignor body information shall refer to the maximum size and only the positions necessary for its storage shall be used, from left to right.

Therefore, it is not enough to just put the number on this OID. Applications that read certificate data look for the fields in the correct positions, and putting fields in wrong formats will not work.

Another point is that eCPF should also have Oids 2.16.76.1.3.5 and 2.16.76.1.3.6, whose formats are also described in detail in the same document you quoted.

There are also details about the order in which these Oids appear. The Certificate Policies of AC Serasa and of AC Certisign, for example, they say that the order of Oids should be 2.16.76.1.3.1, 2.16.76.1.3.6 and 2.16.76.1.3.5. Already the document you quoted says nothing about the order of the same.


Already the eCNPJ should have the Oids 2.16.76.1.3.4, 2.16.76.1.3.2, 2.16.76.1.3.3 and 2.16.76.1.3.7 (and again, AC’s mention that it should be in this order, but the Recipe document does not), and each has its own format, in a similar way to the eCPF fields.

And how I love it?

The keytool has the option -ext to place extensions in the certificate. How Oids are in the extension Subject Alternative Name, just put this extension. Something like this:

keytool -genkeypair ..... -ext san=oid:2.16.76.1.3.1,oid:2.16.76.1.3.6,oid:2.16.76.1.3.5

Unfortunately, I was unable to pass the values to the Oids, as the keytool seems to only support the OID number itself as the value.

So the way is to use Java itself. I made a code that generates an AC certificate of any kind (saving the files "actest.jks", with the AC private key, and "actest.cer", with the AC certificate, in case you need to add in some truststore, for example).

Then I use the private key that is in "actest.jks" and use it to generate an e-CPF or e-CNPJ (also saving in PFX and .cer with only the certificate). The detail is that I used the Bouncy Castle, a library that I recommend much to work with certificates (and encryption in general). As I am using Maven, I put these dependencies:

<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk15on</artifactId>
    <version>1.57</version>
</dependency>
<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcmail-jdk15on</artifactId>
    <version>1.57</version>
</dependency>
<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bctls-jdk15on</artifactId>
    <version>1.57</version>
</dependency>
<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcpg-jdk15on</artifactId>
    <version>1.57</version>
</dependency>

But if you want, you can download this version on the website https://www.bouncycastle.org/.

As I originally made this code in Java 7, I also used the Threeten Backport, which is a date library:

<dependency>
    <groupId>org.threeten</groupId>
    <artifactId>threetenbp</artifactId>
    <version>1.3.6</version>
</dependency>

But if you’re using Java >= 8, you can remove it and use the package java.time (there are comments in the code about this, but basically just change the import of org.threeten.bp for java.time, except in the case of the class DateTimeUtils, which is commented below how to proceed).

First the class that creates the certificate and CA keys:

import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;

import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.BasicConstraints;
import org.bouncycastle.asn1.x509.CertificatePolicies;
import org.bouncycastle.asn1.x509.ExtendedKeyUsage;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.KeyPurposeId;
import org.bouncycastle.asn1.x509.KeyUsage;
import org.bouncycastle.asn1.x509.PolicyInformation;
import org.bouncycastle.asn1.x509.PolicyQualifierId;
import org.bouncycastle.asn1.x509.PolicyQualifierInfo;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils;
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.jcajce.JcaPEMWriter;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.threeten.bp.DateTimeUtils;
import org.threeten.bp.Instant;
import org.threeten.bp.temporal.ChronoUnit;

public class CriarAcTest {

    private static JcaX509ExtensionUtils extUtils;

    static SecureRandom rand;
    static {
        Security.addProvider(new BouncyCastleProvider());
        try {
            rand = SecureRandom.getInstance("SHA1PRNG");
            extUtils = new JcaX509ExtensionUtils();
        } catch (NoSuchAlgorithmException e) {
            rand = new SecureRandom();
        }
    }

    /**
     * Cria um novo certificado de AC (a partir do qual serão emitidos outros certificados)
     */
    public static void main(String[] args) throws Exception {
        KeyPair acKeyPair = genKeyPair(4096);

        String acSubject = "C=BR,O=TRT2,CN=AC Test";
        // criar AC com validade de 30 anos (365 * 30)
        X509Certificate acCert = createAcCert(acSubject, new BigInteger("1234"), 365 * 30, acKeyPair);
        saveToKeystore(acCert, acKeyPair.getPrivate(), "actest.jks", "JKS");
        saveToFile(acCert, "actest.cer");

        System.out.println(acCert);
    }

    static void saveToKeystore(X509Certificate certificate, PrivateKey privKey, String file, String type) throws Exception {
        char[] password = "123456".toCharArray();
        KeyStore ks = KeyStore.getInstance(type);
        ks.load(null, password);

        ks.setKeyEntry("main", privKey, password, new Certificate[] { certificate });

        OutputStream out = new FileOutputStream(file);
        ks.store(out, password);
        out.close();
    }

    static void saveToFile(X509Certificate cert, String filename) throws IOException {
        JcaPEMWriter pw = new JcaPEMWriter(new FileWriter(filename));
        pw.writeObject(cert);
        pw.close();
    }

    static X509Certificate createAcCert(String subject, BigInteger serialNumber, int validityInDays, KeyPair keyPair) throws Exception {
        X500Name issuer = new X500Name(subject);
        // data-inicio 24 horas antes, pra evitar dessincronizacao entre maquinas, horario de verao
        Instant validityStart = Instant.now().minus(24, ChronoUnit.HOURS);
        Instant validityEnd = validityStart.plus(validityInDays, ChronoUnit.DAYS);
        X509v3CertificateBuilder certBuilder = new JcaX509v3CertificateBuilder(issuer, serialNumber,
           // se estiver usando Java >= 8, use o java.time e troque esta linha para Date.from(validityStart), Date.from(validityEnd)
           DateTimeUtils.toDate(validityStart), DateTimeUtils.toDate(validityEnd),
           issuer, keyPair.getPublic());

        KeyUsage usage = new KeyUsage(
            KeyUsage.digitalSignature | KeyUsage.keyEncipherment | KeyUsage.dataEncipherment | KeyUsage.keyCertSign | KeyUsage.cRLSign);
        certBuilder.addExtension(Extension.keyUsage, false, usage);

        ExtendedKeyUsage eku = new ExtendedKeyUsage(new KeyPurposeId[] { KeyPurposeId.id_kp_OCSPSigning, KeyPurposeId.id_kp_timeStamping });
        certBuilder.addExtension(Extension.extendedKeyUsage, false, eku);

        BasicConstraints bc = new BasicConstraints(true);
        certBuilder.addExtension(Extension.basicConstraints, true, bc);

        boolean isCritical = true;
        PolicyQualifierInfo pqInfo = new PolicyQualifierInfo("http://www.test.com");
        PolicyInformation policyInfo = new PolicyInformation(PolicyQualifierId.id_qt_cps, new DERSequence(pqInfo));
        CertificatePolicies policies = new CertificatePolicies(policyInfo);
        certBuilder.addExtension(Extension.certificatePolicies, isCritical, policies);

        certBuilder.addExtension(Extension.subjectKeyIdentifier, true, extUtils.createSubjectKeyIdentifier(keyPair.getPublic()));

        certBuilder.addExtension(Extension.authorityKeyIdentifier, true, extUtils.createAuthorityKeyIdentifier(keyPair.getPublic()));

        ContentSigner signer = new JcaContentSignerBuilder("SHA512WithRSAEncryption").setProvider(BouncyCastleProvider.PROVIDER_NAME)
            .build(keyPair.getPrivate());
        X509Certificate cert = new JcaX509CertificateConverter().setProvider(BouncyCastleProvider.PROVIDER_NAME).getCertificate(certBuilder.build(signer));

        return cert;
    }

    static KeyPair genKeyPair(int size) throws NoSuchAlgorithmException, NoSuchProviderException {
        KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA", BouncyCastleProvider.PROVIDER_NAME);
        gen.initialize(size, rand);
        return gen.generateKeyPair();
    }
}

Code that reads the AC certificate and generates an eCPF (you can change the main to generate an eCNPJ as well, just change the parameters):

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;

import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Object;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.DERPrintableString;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.asn1.DERTaggedObject;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.ExtendedKeyUsage;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.asn1.x509.KeyPurposeId;
import org.bouncycastle.asn1.x509.KeyUsage;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils;
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.jcajce.JcaPEMWriter;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.threeten.bp.DateTimeUtils;
import org.threeten.bp.Instant;
import org.threeten.bp.temporal.ChronoUnit;

public class CriarCertificadoTest {

    private static JcaX509ExtensionUtils extUtils;

    static SecureRandom rand;

    static {
        Security.addProvider(new BouncyCastleProvider());
        try {
            rand = SecureRandom.getInstance("SHA1PRNG");
            extUtils = new JcaX509ExtensionUtils();
        } catch (NoSuchAlgorithmException e) {
            rand = new SecureRandom();
        }
    }

    /**
     * Cria um certificado de teste.
     *
     * O certificado é emitido pela AC criada pela classe {@link CriarAcTest}
     */
    public static void main(String[] args) throws Exception {
        KeyPair myKeyPair = genKeyPair(2048);

        String acSubject = "C=BR,O=TRT2,CN=AC Test";
        char[] password = "123456".toCharArray();
        KeyStore ks = KeyStore.getInstance("JKS");
        // carrega o certificado da AC
        InputStream in = new FileInputStream("actest.jks");
        ks.load(in, password);
        in.close();

        // obtém o certificado e as chaves da AC
        X509Certificate acCert = (X509Certificate) ks.getCertificate("main");
        KeyPair acKeyPair = new KeyPair(acCert.getPublicKey(), (PrivateKey) ks.getKey("main", password));

        System.out.println(acCert);

        // mudar os dados conforme necessário
        String cpf = "23446147292";
        String filename = "cpf" + cpf;
        String nome = "FULANO DE TAL";
        filename = "certificado_" + cpf; // nome do PFX e .cer
        // validade do certificado (em dias) - a data inicial é a atual menos 24 horas
        int validityDays = 365 * 3;
        X509Certificate cert = createCert("C=BR,O=ICP-Brasil,OU=AR Teste,OU=RFB e-CPF A3,OU=TESTE,CN=" + nome + ":" + cpf,
                new BigInteger("3333333333", 16), validityDays, myKeyPair, acKeyPair, acSubject, cpf, acCert);
        saveToKeystore(cert, myKeyPair.getPrivate(), filename + ".pfx", "PKCS12", acCert);
        saveToFile(cert, filename + ".cer");

        System.out.println(cert);
    }

    static void saveToKeystore(X509Certificate certificate, PrivateKey privKey, String file, String type, X509Certificate acCert) throws Exception {
        char[] password = "123456".toCharArray();
        KeyStore ks = KeyStore.getInstance(type);
        ks.load(null, password);

        ks.setKeyEntry("main", privKey, password, new Certificate[] { certificate, acCert });

        OutputStream out = new FileOutputStream(file);
        ks.store(out, password);
        out.close();
    }

    static void saveToFile(X509Certificate cert, String filename) throws IOException {
        JcaPEMWriter pw = new JcaPEMWriter(new FileWriter(filename));
        pw.writeObject(cert);
        pw.close();
    }

    public static X509Certificate createCert(String subject, BigInteger serialNumber, int validityInDays, KeyPair myKeyPair, KeyPair acKeyPair,
            String acSubject, String cpf, X509Certificate acCert)
            throws Exception {
        // data-inicio 24 horas antes, pra evitar dessincronizacao entre maquinas, horario de verao
        Instant validityStart = Instant.now().minus(24, ChronoUnit.HOURS);
        Instant validityEnd = validityStart.plus(validityInDays, ChronoUnit.DAYS);
        // data de validade do certificado não pode ser maior que da AC
        // a partir do Java 8, troque esta linha por acCert.getNotAfter().toInstant();
        Instant validadeAC = DateTimeUtils.toInstant(acCert.getNotAfter());
        if (!validityEnd.isBefore(validadeAC)) {
            validityEnd = validadeAC.minus(24 * 20, ChronoUnit.HOURS);
        }
        X509v3CertificateBuilder certBuilder = new JcaX509v3CertificateBuilder(new X500Name(acSubject), serialNumber,
            // se estiver usando Java >= 8, use o java.time e troque esta linha para Date.from(validityStart), Date.from(validityEnd)
            DateTimeUtils.toDate(validityStart), DateTimeUtils.toDate(validityEnd),
            new X500Name(subject), myKeyPair.getPublic());

        KeyUsage usage = new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyEncipherment | KeyUsage.nonRepudiation);
        certBuilder.addExtension(Extension.keyUsage, false, usage);

        ExtendedKeyUsage eku = new ExtendedKeyUsage(new KeyPurposeId[] { KeyPurposeId.id_kp_clientAuth });
        certBuilder.addExtension(Extension.extendedKeyUsage, false, eku);

        certBuilder.addExtension(Extension.subjectKeyIdentifier, false, extUtils.createSubjectKeyIdentifier(myKeyPair.getPublic()));

        certBuilder.addExtension(Extension.authorityKeyIdentifier, false, extUtils.createAuthorityKeyIdentifier(acKeyPair.getPublic()));

        // --------------------------------------------------------------------
        // Subject Alternative Names
        ASN1EncodableVector subjAltNames = new ASN1EncodableVector();

        // OID 1
        ASN1EncodableVector otherName = new ASN1EncodableVector();
        otherName.add(new ASN1ObjectIdentifier("2.16.76.1.3.1"));
        // data de nascimento
        StringBuilder strOid1 = new StringBuilder("10101970")
                // CPF
                .append(cpf)
                // nis
                .append("00000000000")
                // RG
                .append("000000226148452SSPSP");
        otherName.add(new DERTaggedObject(true, 0, new DERPrintableString(strOid1.toString())));
        ASN1Object oid1 = new DERTaggedObject(false, GeneralName.otherName, new DERSequence(otherName));
        subjAltNames.add(oid1);

        // OID 6
        otherName = new ASN1EncodableVector();
        otherName.add(new ASN1ObjectIdentifier("2.16.76.1.3.6"));
        // CEI
        String strOid6 = "000000000000";
        otherName.add(new DERTaggedObject(true, 0, new DERPrintableString(strOid6)));
        ASN1Object oid6 = new DERTaggedObject(false, GeneralName.otherName, new DERSequence(otherName));
        subjAltNames.add(oid6);

        // OID 5
        otherName = new ASN1EncodableVector();
        otherName.add(new ASN1ObjectIdentifier("2.16.76.1.3.5"));
        // titulo de eleitor
        StringBuilder strOid5 = new StringBuilder("850544450191")
                // zona eleitoral
                .append("001")
                // secao
                .append("0401")
                // municipio e UF
                .append("SAO PAULOSP");
        otherName.add(new DERTaggedObject(true, 0, new DERPrintableString(strOid5.toString())));
        ASN1Object oid5 = new DERTaggedObject(false, GeneralName.otherName, new DERSequence(otherName));
        subjAltNames.add(oid5);

        certBuilder.addExtension(Extension.subjectAlternativeName, false, new DERSequence(subjAltNames));
        // --------------------------------------------------------------------

        ContentSigner signer = new JcaContentSignerBuilder("SHA256WithRSAEncryption").setProvider(BouncyCastleProvider.PROVIDER_NAME)
                .build(acKeyPair.getPrivate());
        X509Certificate cert = new JcaX509CertificateConverter().setProvider(BouncyCastleProvider.PROVIDER_NAME).getCertificate(certBuilder.build(signer));

        return cert;
    }

    public static X509Certificate createCertPJ(String subject, BigInteger serialNumber, int validityInDays, KeyPair myKeyPair, KeyPair acKeyPair,
            String acSubject, String cpfResp, String nomeResp, String cnpj, X509Certificate acCert)
            throws Exception {
        // data-inicio 24 horas antes, pra evitar dessincronizacao entre maquinas, horario de verao
        Instant validityStart = Instant.now().minus(24, ChronoUnit.HOURS);
        Instant validityEnd = validityStart.plus(validityInDays, ChronoUnit.DAYS);
        // data de validade do certificado não pode ser maior que da AC
        // a partir do Java 8, troque esta linha por acCert.getNotAfter().toInstant();
        Instant validadeAC = DateTimeUtils.toInstant(acCert.getNotAfter());
        if (!validityEnd.isBefore(validadeAC)) {
            validityEnd = validadeAC.minus(24 * 20, ChronoUnit.HOURS);
        }
        X509v3CertificateBuilder certBuilder = new JcaX509v3CertificateBuilder(new X500Name(acSubject), serialNumber,
            // se estiver usando Java >= 8, use o java.time e troque esta linha para Date.from(validityStart), Date.from(validityEnd)
            DateTimeUtils.toDate(validityStart), DateTimeUtils.toDate(validityEnd),
            new X500Name(subject), myKeyPair.getPublic());

        KeyUsage usage = new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyEncipherment | KeyUsage.nonRepudiation);
        certBuilder.addExtension(Extension.keyUsage, false, usage);

        ExtendedKeyUsage eku = new ExtendedKeyUsage(new KeyPurposeId[] { KeyPurposeId.id_kp_clientAuth });
        certBuilder.addExtension(Extension.extendedKeyUsage, false, eku);

        certBuilder.addExtension(Extension.subjectKeyIdentifier, false, extUtils.createSubjectKeyIdentifier(myKeyPair.getPublic()));

        certBuilder.addExtension(Extension.authorityKeyIdentifier, false, extUtils.createAuthorityKeyIdentifier(acKeyPair.getPublic()));

        // --------------------------------------------------------------------
        // Subject Alternative Names
        ASN1EncodableVector subjAltNames = new ASN1EncodableVector();

        // OID 4
        ASN1EncodableVector otherName = new ASN1EncodableVector();
        otherName.add(new ASN1ObjectIdentifier("2.16.76.1.3.4"));
        // data de nascimento
        StringBuilder strOid1 = new StringBuilder("10101970")
                // CPF
                .append(cpfResp)
                // nis
                .append("00000000000")
                // RG
                .append("000000226148452SSPSP");
        otherName.add(new DERTaggedObject(true, 0, new DERPrintableString(strOid1.toString())));
        ASN1Object oid4 = new DERTaggedObject(false, GeneralName.otherName, new DERSequence(otherName));
        subjAltNames.add(oid4);

        // OID 2
        otherName = new ASN1EncodableVector();
        otherName.add(new ASN1ObjectIdentifier("2.16.76.1.3.2"));
        // Nome do responsavel
        otherName.add(new DERTaggedObject(true, 0, new DERPrintableString(nomeResp)));
        ASN1Object oid2 = new DERTaggedObject(false, GeneralName.otherName, new DERSequence(otherName));
        subjAltNames.add(oid2);

        // OID 3
        otherName = new ASN1EncodableVector();
        otherName.add(new ASN1ObjectIdentifier("2.16.76.1.3.3"));
        // CNPJ
        otherName.add(new DERTaggedObject(true, 0, new DERPrintableString(cnpj)));
        ASN1Object oid3 = new DERTaggedObject(false, GeneralName.otherName, new DERSequence(otherName));
        subjAltNames.add(oid3);

        // OID 7
        otherName = new ASN1EncodableVector();
        otherName.add(new ASN1ObjectIdentifier("2.16.76.1.3.7"));
        // CEI
        String strOid7 = "000000000000";
        otherName.add(new DERTaggedObject(true, 0, new DERPrintableString(strOid7)));
        ASN1Object oid7 = new DERTaggedObject(false, GeneralName.otherName, new DERSequence(otherName));
        subjAltNames.add(oid7);

        certBuilder.addExtension(Extension.subjectAlternativeName, false, new DERSequence(subjAltNames));
        // --------------------------------------------------------------------

        ContentSigner signer = new JcaContentSignerBuilder("SHA256WithRSAEncryption").setProvider(BouncyCastleProvider.PROVIDER_NAME)
                .build(acKeyPair.getPrivate());
        X509Certificate cert = new JcaX509CertificateConverter().setProvider(BouncyCastleProvider.PROVIDER_NAME).getCertificate(certBuilder.build(signer));

        return cert;
    }

    public static KeyPair genKeyPair(int size) throws NoSuchAlgorithmException, NoSuchProviderException {
        KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA", BouncyCastleProvider.PROVIDER_NAME);
        gen.initialize(size, rand);
        return gen.generateKeyPair();
    }
}

I made this code some time ago and to run a few times, which is a great excuse to be so full of redundancies and without any optimization. Feel free to change it.

  • Thank you very much.

  • I’ll test it here. I would fix the OID part contain more things but as I don’t have many points on stackoverflow yet I don’t have editing permission.

  • @Gladsonbruno Which part were you going to correct? If it was in my reply, you can suggest an edition. Feel free to fix, it’s been a while since I read these pdf’s and I may have missed some detail

  • would be the correction of the OID description that I had said contained only the CPF and the formatting of the entire question that came out unformatted. I believe I’ve got the editing privilege now.

  • 1

    hktosubo Thank you very much. Solve my problem with certificate E-CPF I was hours away looking for how to do this in keytool

  • I’m having a different problem, the generated customer certificate worked, however the chain of certificates I tried to generate is not valid, could you take a look @hkotsubo? https://answall.com/questions/382087/gerar-certificados-a1-para-teste-no-padr%C3%a3o-icp-brasil

Show 1 more comment

Browser other questions tagged

You are not signed in. Login or sign up in order to post.