How to extract CNPJ from A1 . pfx or . P12 Digital Certificate on Linux and Windows using . NET Core?

Asked

Viewed 84 times

0

I’m developing a system where we register companies by digital certificate, where the user uploads the file, puts the password and imports. I need to extract the CNPJ that is within the certificate to consult the Company’s data in the Internal Revenue Service and register.

The system aims to consult Tax Documents in Sefaz, so we need the Certificate and Company data.

On a Windows machine (in my development environment), was using this method to extract CNPJ and was working:

public static string ExtrairCNPJArquivo(X509Certificate2 arquivo)
{
  const string oid = "2.16.76.1.3.3";
  StringBuilder cnpj = new StringBuilder();

  foreach (X509Extension extension in arquivo.Extensions)
  {
    string texto = extension.Format(true);
    string[] linhas = texto.Split(new char[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);

    for (int i = 0; i < linhas.Length; i++)
    {
      if (linhas[i].Trim().StartsWith(oid))
      {
        string valores = linhas[i].Substring(linhas[i].IndexOf('=') + 1);
        string[] elementos = valores.Split(' ');

        byte[] cnpjBytes = new byte[14];

        for (int j = 0; j < cnpjBytes.Length; j++)
          cnpjBytes[j] = Convert.ToByte(elementos[j + 2], 16);

        cnpj.Append(Encoding.UTF8.GetString(cnpjBytes));

        break;
      }
    }

    if (!string.IsNullOrEmpty(cnpj.ToString()))
      break;
  }

  return cnpj.ToString();
}

But in my production environment, I use a Linux machine that runs on Docker, and this form used above doesn’t work for that platform. The text of extension.Format(true); was coming as othername:<unsupported> and that’s where the CNPJ of the Certificate comes from. Then I saw that Linux doesn’t work that way.

How can I make it work on both platforms?

1 answer

0

After having searched hard and not found an answer, I did so and works for both platforms:

public static string ExtrairCNPJArquivo(X509Certificate2 certificado)
{
    const string oIdSubjectAlternativeName = "2.5.29.17";

    var extensao = certificado.Extensions[oIdSubjectAlternativeName];
    var texto = Encoding.UTF8.GetString(extensao.RawData);

    var matches = Regex.Matches(texto, @"(?<!\d)\d{14}(?!\d)");
    var cnpjValido = matches.FirstOrDefault(p => p.Value.ValidarCnpj());

    return cnpjValido?.Value;
}

I tested on my local Windows machine, and also climbed on Docker Linux and it worked that way.

CNPJ is inside Extension Subjectalternativename, so let’s go straight to this Extension, take the byte, convert to string and search for CNPJ using the regex that only brings numbers that have 14 characters.

We thought it might have more than a 14-character number, so to improve, you can use the Regex.Matches, and validate which CNPJ is correct, if more than one match. But this is a very difficult scenario to happen; I left it that way so that if it happens one day, the code is already prepared.

To validate the CNPJ (case wanted, also CPF), see this link: https://gist.github.com/rdakar/dba890b5e2cbdeb7c62c0dee9f627a7f

Browser other questions tagged

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