Criptografia em AdvPL – Parte 16

Introdução

No post anterior (Criptografia em AdvPL – Parte 15) vimos assinatura digital S/MIME e a função SMimeSign(). Agora, vamos entrar na no universo das funções criptográficas usando um HSM — Hardware Security Module — e o que podemos fazer com isso no AdvPL 😀 Para ver o índice de tudo o que já foi publicado nessa série de posts, acesse o link Criptografia e Segurança.

HSM

Agora que já vimos bastante coisa sobre criptografia, chaves e certificados, o ponto comum dos exemplos e funções abordadas é : Os certificados e chaves até o momento foram salvas em arquivos em disco, e usamos funções criptográficas de alguma aplicação — seja o OpenSSL ou o TOTS Application Server — para carregar e usar estes arquivos.

Quando utilizamos um equipamento do tipo HSM, ao invés de eu carregar o certificado e usá-lo na minha aplicação, eu uso um Driver ou API do dispositivo, para cadastrar nele as chaves e certificados que eu vou utilizar — e quero manter protegidos — e então eu uso uma API Cliente do Driver ou Dispositivo para consumir os certificados e chaves. O TOTVS Application Server permite configurar um driver de dispositivo HSM e disponibiliza funções específicas no AdvPL para utilizá-lo. Vamos ver neste post o que é isso e como funciona 😀

API Client do HSM / Cryptoki

O padrão PKCS#11 define uma especificação de APIs para consumir os serviços de um HSM. Normalmente o fornecedor do hardware HSM disponibiliza uma API ou library (dll/so) Client do dispositivo neste padrão, possibilitando a implementação final — uma mesma implementação de criptografia pode ser feita para vários modelos de HSM. Esta API é conhecida com “Cryptoki Library”, e possui as funções padronizadas na especificação PKCS11 para serem consumidas por uma aplicação final.

Para fazer os testes e programas de exemplo, eu não necessariamente preciso de um Hardware HSM, eu posso usar um emulador do hardware e a Cryptoki fornecida pelo fabricante, ou mesmo usar uma implementação Open-Source que emule um HSM. Após algumas pesquisas, optei por usar um pacote “pronto” para Windows — SoftHSM2 — baseado no projeto OpenDNSSEC.

SoftHSM2

Disponível em diversas plataformas, os links de download estão disponíveis em https://www.opendnssec.org/download/packages/ . A build Windows que será utilizada pode ser baixada no link https://github.com/disig/SoftHSM2-for-Windows/ . Optei por pegar a versão completa já com instalador, que configura algumas variáveis de ambiente necessárias para a API, instalação default no path sugerido “c:\SoftHSM2′.

Teste inicial com o TOTVS Application Server

Instalado o SoftHSM2 com as configurações default, a DLL com a implementação da API com as funções PKCS#11 deve estar na pasta “C:\SoftHSM2\lib”. Para usar com um TOTVS Application Server de 32 bits, usamos o arquivo “softhsm2.dll“, e para uso com Application Server 64 bits, usamos o arquivo “softhsm2-x64.dll“. No meu ambiente, eu uso o P12 Lobo Guará x64. Logo, vamos configurar a seção SSLConfigure com os seguintes parâmetros:

[sslconfigure]
HSM=1
Module=C:\SoftHSM2\lib\softhsm2-x64.dll
verbose=1

Ao subir o TOTVS Application Server, aparecem algumas informações novas no log e console:

[INFO ][SSL] Configuring to use HSM
[INFO ][SSL] Criptoki Path : supplied (C:\SoftHSM2\lib\softhsm2-x64.dll)
[INFO ][SSL] PIN : supplied
[INFO ][SSL] VERBOSE : ENABLE
[WARN ][SSL] Private Key Client not supplied
[INFO ][SSL] Private Key Client: ENABLE ((null))
[WARN ][SSL] Certificate Client not supplied
[INFO ][SSL] Certificate Client : ENABLE ((null))
[INFO][PKCS11] Found 1 slot
[0] SoftHSM slot ID 0x0 uninitialized, login (no label)
[INFO ][SSL] Status HSM : ENABLE


Por hora este teste apenas garante que utilizamos uma DLL suportada. A documentação da chave “module” da seção sslconfigure  na TDN informa que a DLL informada precisa suportar as funções da PKCS#11 com versão igual ou superior a V 2.10.

Próximos passos

Bem, um dispositivo HSM trabalha com um conceito de SLOTS, onde cada slot pode conter objetos para uso criptográfico, como chaves privadas e certificados. Normalmente o fabricante fornece um SDK com ferramentas de desenvolvimento e de administração do HSM, para que você — de forma assistida — possa gerenciar e armazenar os certificados e chaves de seu uso em um ou mais slots, se for o caso.

No nosso exemplo estamos usando um Software para este armazenamento, emulando um HSM. Logo, precisamos descobrir como usar as ferramentas desse software para armazenar os nossos certificados e chaves.

Ferramenta softhsm2-util

No nosso exemplo de HSM virtual, a ferramenta de linha de comando softhsm2-util vai ser útil para realizar esta tarefa. Inicialmente, vamos ver o que temos registrado no momento, usando o comando abaixo — lembre-se de colocar o caminho “c:\SoftHSM2\bin” no PATH do seu ambiente.

softhsm2-util --show-slots

// resultado obtido
Available slots:
Slot 0
    Slot info:
        Description:      SoftHSM slot ID 0x0
        Manufacturer ID:  SoftHSM project
        Hardware version: 2.5
        Firmware version: 2.5
        Token present:    yes
    Token info:
        Manufacturer ID:  SoftHSM project
        Model:            SoftHSM v2
        Hardware version: 2.5
        Firmware version: 2.5
        Serial number:
        Initialized:      no
        User PIN init.:   no
        Label:

Bem, nos exemplos anteriores criamos um certificado e uma chave privada para HTTPS, chamados respectivamente de “note-juliow-ssd.key” e “note-juliow-ssd.cer”. Vamos começar a brincadeira criando um SLOT no nosso HSM virtual para gravar estas informações:

softhsm2-util --init-token --slot 0 --label "Minhas Chaves" --so-pin 666666 --pin 123456

// Resultado obtido

The token has been initialized and is reassigned to slot 1910125011

No caso, um novo slot foi criado, onde eu informei um PIN de administração ( 666666 ) e um PIN de acesso de usuário ( 123456 ) . Ao executarmos o comando para mostrar os slots, veremos o seguinte:

softhsm2-util --show-slots

Available slots:
Slot 1910125011
    Slot info:
        Description:      SoftHSM slot ID 0x46a35bd7
        Manufacturer ID:  SoftHSM project
        Hardware version: 2.5
        Firmware version: 2.5
        Token present:    yes
    Token info:
        Manufacturer ID:  SoftHSM project
        Model:            SoftHSM v2
        Hardware version: 2.5
        Firmware version: 2.5
        Serial number:    83007bde71da31d3
        Initialized:      yes
        User PIN init.:   yes
        Label:            Minhas Chaves
Slot 1
    Slot info:
        Description:      SoftHSM slot ID 0x1
        Manufacturer ID:  SoftHSM project
        Hardware version: 2.5
        Firmware version: 2.5
        Token present:    yes
    Token info:
        Manufacturer ID:  SoftHSM project
        Model:            SoftHSM v2
        Hardware version: 2.5
        Firmware version: 2.5
        Serial number:
        Initialized:      no
        User PIN init.:   no
        Label:

O novo slot criado recebeu um número de controle, o label ou título “Minhas Chaves”, usando os PIN(s) informados, e ganhou um número de série.

Importando uma Chave Privada para o HSM

Agora, vamos ver como colocar uma chave privada nesse slot. Para isso, na pasta onde está o arquivo “note-juliow-ssd.key”, execute o  comando abaixo:

softhsm2-util --import note-juliow-ssd.key --label "Note-Key" --slot 1910125011 --id a001 --pin 123456 --no-public-key

The key pair has been imported.

No comando acima fornecemos a chave privada a ser importada ( Formato PEM PKCS#8), o slot criado anteriormente, um título para a chave — “Note-Key”, e o PIN de usuário (123456) para permitir a operação, um identificador em hexadecimal que eu criei (a001) e a opção para importar apenas a chave privada (–no-public-key).

Importando um certificado para o HSM

Bem, para eu importar o certificado para esse HSM Virtual, os aplicativos de linha de comando são “limitados”, então eu tive que baixar um “Administrador Genérico” de HSM(s) para Windows — chamado Pkcs11Admin — vide maiores detalhes nos links de referência.

O certificado utilizado foi o anteriormente criado para HTTPS — chamado “note-juliow-ssd.cer”. Ao iniciarmos a ferramenta Pkcs11Admin, devemos informar onde está a DLL do SoftHSM — que é o “dispositivo virtual” utilizado:

pkcs11-1

Lembre-se que o PKCS11Admin usado deve ser compatível em 32 ou 64 bits com a DLL do SoftHSM. Feito isso, vamos no Menu Token -> Login -> User Login, e entramos com o PIN de usuário (123456):

pkcs11-2

Agora podemos posicionar na aba “Keys”, e ver que já temos uma chave importada neste slot:

pkcs11-3

Para importar o certificado, vamos no menu Object -> Import -> Certificate. Será aberta uma caixa de diálogo para localizar o certificado a ser importado no disco. Ao escolher o certificado, a ferramenta mostra os dados do certificado, e até permite editar alguns. Como não é o caso ou objetivo, apenas confirmamos a operação clicando no botão “Create”:

pkcs11-4.png

Feito isso, o certificado já está visível na aba “Certificates”, basta clicar nele com o botão direito e escolher a opção  “View” para conferirmos os detalhes dele:

pkcs11-5

Agora pode fechar o PKCS11Admin, e vamos ver a subida do TOTVS Application Server com o HSM configurado e alimentado:

[INFO][PKCS11] Found 2 slots
[0] SoftHSM slot ID 0x71da31d  login             (Minhas Chaves)
[1] SoftHSM slot ID 0x1        uninitialized, login  (no label)

[INFO ][SSL] Status HSM : ENABLE

Conclusão

Beleza, agora já temos uma “base” para, no próximo post, ver como listar os slots e dados armazenados no HSM, e como recuperá-los para uso no AdvPL 😀  Está curioso ? Então dê uma olhada nas funções HSMSlotList e HSMObjList, elas serão as “primeiras” 😉

A saga HSM continua no próximo Post, e como sempre desejo de coração a todos TERABYTES DE SUCESSO !!! 

Referências

 

Criptografia em AdvPL – Parte 15

Introdução

No post anterior (Criptografia em AdvPL – Parte 14) vimos mais funções de assinatura digital, módulo e expoente das chaves criptográficas, e a diferença entre uma PUBLIC KEY e uma RSA PUBLIC KEY. Agora, vamos ver mais uma forma de assinar digitalmente no AdvPL 😀 Para ver o índice de tudo o que já foi publicado nessa série de posts, acesse o link Criptografia e Segurança.

É possível assinar outros conteúdos no AdvPL ?

Sim, o AdvPL ainda oferece a função SMimeSign(), criada para assinar conteúdos em formato MIME (Multipurpose Internet Mail Extensions) – usados para e-mails e afins — através de um certificado digital junto com uma chave criptográfica privada.

Função AdvPL SMimeSign()

Documentada no TDN no link https://tdn.totvs.com/display/tec/SMIMESign, ela permite assinar de várias formas um conteúdo em formato MIME — como um e-mail por exemplo — ou mesmo um texto plano, ou outro conteúdo qualquer. A primeira diferença importante desta função para as demais é que o certificado e a chave privada devem ser informados com o caminho completo (unidade de disco + path), sendo assim o certificado e a chave usados não precisam estar dentro do RootPath do ambiente.Vamos ver como utilizá-la na série de exemplos a seguir.

Requisitos

Para os próximos testes, vamos utilizar o mesmo certificado e chave privada de exemplo usado para o HTTPS dos posts anteriores  (note-juliow-ssd.cer e note-juliow-ssd.key).

Equivalência com a OpenSSL

A ferramenta de linha de comando OpenSSL possui o comando “smime”, que permite não apenas assinar um conteúdo, mas criptografá-lo, descriptografá-lo e verificar a validade de uma assinatura, e por default o formato de saída (output) da instrução de assinatura é SMIME. A função SMimeSign() engloba apenas a opção de assinatura, e o formato de retorno é PKCS7 PEM — codificado em Base64.

Primeira assinatura

Eu tenho uma mensagem em texto plano, apenas a string “Meu teste de assinatura MIME”, e quero gerar uma assinatura desse texto usando meu certificado de testes e a chave privada desse certificado. Para fazer isso em um fonte AdvPL, eu posso proceder por exemplo da seguinte forma:

User Function MSign1()
local cSignCert := "C:\Protheus12LG\EnvLight\certificates\note-juliow-ssd.cer"
local cPrivKey := "C:\Protheus12LG\EnvLight\certificates\note-juliow-ssd.key"
local cData := 'Meu teste de assinatura MIME'
local cError := ""
local cSigned := ""

cSigned := SMIMESign( cSignCert, cPrivKey, cData, '', @cError, '' )

If empty(cSigned)
  conout("SMIMESign ERROR : "+cError)
Else
  conout("SMIMESign OK ")
  memowrit('\certificates\message_protheus.p7s',cSigned)
Endif
Return

A chave privada usada não está protegida por senha, e a assinatura desse conteúdo será gerada no formato PKCS7 PEM no arquivo “message_protheus.p7s”. Eu posso abrir esse arquivo em um editor de textos simples para visualização, e nele eu devo ver algo assim:

-----BEGIN PKCS7-----
MIIJ2AYJKoZIhvcNAQcCoIIJyTCCCcUCAQExDzANBglghkgBZQMEAgEFADALBgkq
hkiG9w0BBwGgggYSMIIGDjCCA/agAwIBAgIUXql2ONvAPF7P9ovgz3y4XK2HWdkw
(...)

Se eu estivesse gerando essa assinatura usando a ferramenta OpenSSL, eu precisaria apenas criar um arquivo de texto simples — por exemplo mesagem.txt — contendo o texto “Meu teste de assinatura MIME”, e executar o comando abaixo:

openssl smime -sign -in message.txt  -out message_openssl.p7s -signer note-juliow-ssd.cer -inkey note-juliow-ssd.key -outform pem

O certificado digital usado para a assinatura foi informado através do parâmetro “-signer”, a chave privada do certificado informada no parâmetro “-inkey”, e mudamos o formato de saída para PEM usando o parâmetro “-outform”. Simples assim.

E o que têm “dentro” dessa assinatura ?!

Vamos pedir para a OpenSSL mostrar o que tem nessa assinatura, usando o comando abaixo:

openssl pkcs7 -inform PEM -in message_protheus.p7s -print -out message_protheus_info.txt -noout

Com esta instrução usamos o comando pkcs7 da openssl para gerar um arquivo texto (message_protheus_info.txt) com tudo o que têm dentro dessa assinatura .. são quase 13KB de informações em formato “legível”, entre elas o certificado usado para a assinatura, a chave pública do certificado, a assinatura em si, e um digest RSA criptográfico. Um ponto interessante a ser  visto neste momento é que a informação gerada não contém internamente na estrutura o texto que foi assinado, ela representa a assinatura sobre o texto informado.

Opções adicionais e seus comportamentos

A OpenSSL permite informar opções adicionais na linha de comando, normalmente cada opção é uma palavra reservada precedida por um “-” (sinal de “menos”). A função SMimeSign() também permite algumas opções adicionais, colocadas em uma string AdvPL informada para a função no mesmo formato — e quando usadas mais de uma opção simultaneamente, elas devem estar separadas entre si um espaço em branco. Veja abaixo as opções implementadas no AdvPL para a função SMimeSign():

Opção “-nodetach”

Também chamada de “assinatura opaca”, o uso dessa opção — tanto na OpenSSL quando na SMimeSign() — gera uma assinatura colocando o conteúdo da mensagem dentro da assinatura gerada. Com isso, a assinatura em si também contém o conteúdo original — sem criptografia alguma, apenas “embutido” nela.

Opção “-nocerts”

Caso eu não queira que o certificado usado para a assinatura seja gravado junto da assinatura, basta especificar a opção acima. Porém, se o destinatário da mensagem quiser verificar a assinatura, ele deve ter o certificado usado para a assinatura localmente.

Opção “-noattr”

Por default a assinatura inclui algumas informações adicionais, como por exemplo a data da assinatura e uma lista de algoritmos simétricos suportados. Usando a opção “-noattr”, estes atributos não são inseridos.

Opção “-text”

Quando usamos a opção “-nodetach”, e a mensagem assinada é incorporada dentro da assinatura, usar a opção “-text” acrescenta no inicio da mensagem assinada um header informando “Content-Type: text/plain” + CRLF + CRLF

Opção “-binary”

O uso desta opção não realiza a conversão automática das quebras de linha do conteúdo a ser assinado para CRLF. Quando queremos assinar um conteúdo que não está em formato MIME, ou que não deve ser aplicada nenhuma conversão, usamos esta opção.

Outras opções

Aparentemente as demais opções documentadas não tem efeito sobre a assinatura, como por exemplo “-noverify”, “-nochain”“-nosigs”.

Verificando uma assinatura com OpenSSL

Quando a assinatura contempla a mensagem (opção “-nodetach”), podemos verificar a assinatura da mensagem apenas usando o comando abaixo:

openssl smime -verify -inform PEM -in message_protheus.p7s -noverify

A opção “-noverify” indica que não deve ser verificado quem emitiu o certificado que assinou a mensagem, mas apenas a assinatura em si.

Quando queremos verificar uma assinatura de um determinado conteúdo que não está dentro da assinatura — default — precisamos informar a assinatura e o conteúdo a ser verificado:

openssl smime -verify -inform PEM -in message_protheus.p7s -content message.txt -noverify

Conclusão

Acredito que este post chegou na “metade” das funcionalidades criptográficas que podem ser utilizadas em AdvPL, e já temos uma boa “base” de como isso funciona. Agora, a outra metade — que está no forno — vai englobar todas as funções criptográficas que utilizam HSM (Hardware Security Module)  😀

Espero que estas informações lhes sejam úteis e proveitosas, e lhes desejo como sempre TERABYTES DE SUCESSO !!!!

Referências

 

 

 

Criptografia em AdvPL – Parte 14

Introdução

No post anterior (Criptografia em AdvPL – Parte 13) vimos mais detalhes sobre assinatura digital, e as funções PrivSignRSA() e PrivVeryRSA(). Agora, vamos ver as funções EVPPrivSign() e EVPPrivVery(), e mais algumas coisas interessantes ! Para ver o índice de tudo o que já foi publicado nessa série de posts, acesse o link Criptografia e Segurança.

Direto ao ponto

As funções de assinatura e verificação de assinatura vistas anteriormente exigiam que você calculasse o hash criptográfico de um conteúdo, e depois assinasse este hash. As funções EVPPrivSign() e EVPPrivVery() possuem basicamente apenas uma diferença: Você informa diretamente o conteúdo e o tipo do hash criptográfico a ser usado, e a função faz a geração do hash internamente, e ela gera/verifica a assinatura com apenas uma chamada 😀 Vejam a diferença de chamada, baseado nos códigos de exemplo do post anterior:

// Por exemplo, ao invés de 
cHash := SHA1( cStrImage , 1 )
cSignature := PrivSignRSA( "\siga0984\rootca.key", cHash, 2, "" )

// Você chega no mesmo resultado usando:
cSignature := EVPPrivSign( "\siga0984\rootca.key", cStrImage, 3, "" )

Reparem que as funções recebem um parâmetro numérico para indicar o tipo de hash criptográfico utilizado, mas cada função possui a sua tabela de valores e significados. Consulte a documentação das funções no TDN para maiores detalhes — vide links no final do post. E, para realizar a validação de uma assinatura …

// Ao invés de ....
cHash := SHA1( cStrImage , 1 )
lOk := PrivVeryRSA( "\siga0984\rootCA-public.key", cHash, 2, cSignature )

// podemos usar 
lOk := EVPPrivVery( "\siga0984\rootCA-public.key", cStrImage, 3, cSignature, "" )

Logo, se você não vai usar o hash do conteúdo para nada diferente da assinatura, você pode simplesmente gerar a assinatura sobre o conteúdo usando a EVPPrivSign() dizendo qual o tipo do hash que será usado para assinar 😀

Ainda existe mais uma função de assinatura digital no AdvPL, chamada SMimeSign(), que veremos nesta sequência de posts. Agora, vamos ver mais duas funções auxiliares usadas para retornar algumas informações de uma chave privada: RSAExponent() e RSAModulus()

Por dentro das chaves criptográficas – Módulo

Existem informações de uma chave criptográfica — privada ou pública — que podem ser úteis ou necessárias para realizar algumas validações. Internamente  — e visto da forma mais simples possível — uma chave criptográfica RSA é criada a partir de dois números primos escolhidos aleatoriamente, e a partir deles são calculados dois elementos, chamados de “módulo” e “expoente”. O módulo é a parte comum das duas chaves, tanto a privada como a pública.

Em alguns posts para trás eu gerei uma chave privada usando o OpenSSL, e gerei a chave pública a partir da chave privada. Ao consultar o módulo de ambas, elas devem ter o mesmo valor. Veja no exemplo abaixo usando um par de chaves privada e pública gerados anteriormente usando a OpenSSL:

openssl rsa -in note-juliow-ssd.key -modulus -noout

Modulus=BC5B5604E28A5888652286CE3342C4151ACA9B4EAD7E7B42927E64E93B5C30F9DE34B0C3FBE26269E7D73CF1CB78C284DA15C32B222C307D713FD447340A3950D48FBCFA170BEE6E38281A06B338825164BF7BD075EAFDE1F985AC21FAF8EEFBB5(...)

openssl rsa -in note-juliow-ssd-public.key -pubin -modulus -noout

Modulus=BC5B5604E28A5888652286CE3342C4151ACA9B4EAD7E7B42927E64E93B5C30F9DE34B0C3FBE26269E7D73CF1CB78C284DA15C32B222C307D713FD447340A3950D48FBCFA170BEE6E38281A06B338825164BF7BD075EAFDE1F985AC21FAF8EEFBB5(...)

 

Função AdvPL RSAModulus()

A informação do módulo de uma chave privada ou pública também pode ser obtida em AdvPL usando a função RSAModulus(). A única diferença é que o módulo retornado pelo AdvPL está no formato binário (RAW), em uma string contendo os bytes de 0 a 255, enquanto a OpenSSL retorna o módulo em uma string hexadecimal — que podemos converter facilmente, vide exemplo abaixo:

USER Function GetKeyMod()
Local cPrivMod, cPublMod
Local cPrivHex, cPublHex

cPrivMod := RSAModulus( '\certificates\note-juliow-ssd.key', .F. )
If empty(cPrivMod)
  UserException('Falha ao obter o módulo da Chave Privada')
Endif
cPrivHex := Upper(Str2Hex(cPrivMod)) 
conout("MODULUS - Private Key")
conout(cPrivHex) 

cPublMod := RSAModulus( '\certificates\note-juliow-ssd-public.key', .T. )
If empty(cPublMod)
  UserException('Falha ao obter o módulo da Chave Pública')
Endif
cPublHex := Upper(Str2Hex(cPublMod))
conout("MODULUS - Public Key")
conout(cPublHex)

Return

STATIC Function Str2Hex(cBuffer)
Local cRet := '', nI
For nI := 1 to len(cBuffer)
	cRet += padl(__dectohex(asc(substr(cBuffer,nI,1))),2,'0')
Next
Return cRet

No exemplo acima, usando os mesmos arquivos do exemplo da OpenSSL, contendo respectivamente a chave privada e a chave púbica correspondente à chave privada, e obtive os mesmos valores. É importante eu informar corretamente para a função se a chave informada é pública ou privada. Caso isso não seja informado corretamente, a função retorna NIL. Com esse recurso eu consigo verificar se uma determinada chave pública foi gerada a partir de uma chave privada, e também se uma determinada chave é privada ou pública — testando a mesma duas vezes. O resultado do programa acima pode ser visto no log de console do TOTVS Application Server.

*** Observação muito importante ***

Minha primeira tentativa de execução não funcionou. O programa está correto, a chave pública foi gerada a partir da chave privada como manda o figurino usando a OpenSSL, mas mesmo assim a função RSAModulus() retornava NIL quando eu a utilizava com a chave pública ! Então, depois algumas pesquisas …. entendi o que houve 😀

A chave pública usada no exemplo anterior foi gerada a partir da chave privada, usando o seguinte comando:

openssl rsa -in note-juliow-ssd.key -pubout -out note-juliow-ssd-public.key

Resultado obtido:

—–BEGIN PUBLIC KEY—–
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAvFtWBOKKWIhlIobOM0LE
FRrKm06tfntCkn5k6TtcMPneNLDD++JiaefXPPHLeMKE2hXDKyIsMH1xP9RHNAo5
UNSPvPoXC+5uOCgaBrM4glFkv3vQder94fmFrCH6+O77tXlqAvWDFfqVtRgfdudX
QaH3hCO9jDHuAsZYQ2pA/yRBtjPO63utFNBDz7917G1avpSDbtdx7EC4aDbIKpCc
0G5knOY+KG7FO3CkxX3/kQ348vcn3c0EBiw6zngj00MvSXflThMtGIxDXS59cMTb
X9yaseYFNxT4gopaDEciB6thIEODtcyPCZNftDKbGblQNZEru4v3XKZ7Him0cw34
k+nWmpD4SaSriYpWn49r4XtktKr4EWu5kmaqRgRdu10XUuEXNoaAcB9kRUdvEvLL
NyArbDYyp+1am6n6RzSoGnmNHYThKZ6pZJfzg2R5np1yKgUNTljs/yzXxaJcsuYI
Jo4XEuOZLlB/pj/vbKpFCA342/wV9EIpLRPRTCs+ch/pDCq9OGBcJ91jfDKswPAG
hRrcZGfZRLy8g/xlKhoMBHfqKQb43jW6S80jxocRv03M2NAgVChQ3bLjIfKdZxon
ERVukqw8rGZwhjG8VTmF/p9lAinWzDZR8uIVkxNvobVHr8wgx5T+RDdZkJhG/b56
HMGHeleUBdsKYPPKQhsBiTUCAwEAAQ==
—–END PUBLIC KEY—–

Esta chave pública está correta, PORÉM existem algumas formas de codificação para uma chave pública, onde as duas principais são: PKCS#1 — que contém apenas o módulo e o expoente — e PKCS#8, que pode conter mais informações. No resumo, esta chave está no formato PKCS#8, e contém uma informação adicional dos primeiros 32 caracteres da chave, onde está gravado que “o formato interno da chave é PKCS#1” !!

Quando eu gero uma a chave pública usando a OpenSSL — com a parametrização utilizada — o comportamento default é codificar a chave pública no formato PKCS#8. Se eu quero gerar uma chave pública “sequinha”, no formato PKCS#1, eu posso fazer de duas formas:

  • A partir da chave privada, trocando o parametro “-pubout” para “-RSAPublicKey_out”
openssl rsa -in note-juliow-ssd.key -RSAPublicKey_out -out note-juliow-ssd-public_rsa.key

Resultado obtido:

—–BEGIN RSA PUBLIC KEY—–
MIICCgKCAgEAvFtWBOKKWIhlIobOM0LEFRrKm06tfntCkn5k6TtcMPneNLDD++Ji
aefXPPHLeMKE2hXDKyIsMH1xP9RHNAo5UNSPvPoXC+5uOCgaBrM4glFkv3vQder9
4fmFrCH6+O77tXlqAvWDFfqVtRgfdudXQaH3hCO9jDHuAsZYQ2pA/yRBtjPO63ut
FNBDz7917G1avpSDbtdx7EC4aDbIKpCc0G5knOY+KG7FO3CkxX3/kQ348vcn3c0E
Biw6zngj00MvSXflThMtGIxDXS59cMTbX9yaseYFNxT4gopaDEciB6thIEODtcyP
CZNftDKbGblQNZEru4v3XKZ7Him0cw34k+nWmpD4SaSriYpWn49r4XtktKr4EWu5
kmaqRgRdu10XUuEXNoaAcB9kRUdvEvLLNyArbDYyp+1am6n6RzSoGnmNHYThKZ6p
ZJfzg2R5np1yKgUNTljs/yzXxaJcsuYIJo4XEuOZLlB/pj/vbKpFCA342/wV9EIp
LRPRTCs+ch/pDCq9OGBcJ91jfDKswPAGhRrcZGfZRLy8g/xlKhoMBHfqKQb43jW6
S80jxocRv03M2NAgVChQ3bLjIfKdZxonERVukqw8rGZwhjG8VTmF/p9lAinWzDZR
8uIVkxNvobVHr8wgx5T+RDdZkJhG/b56HMGHeleUBdsKYPPKQhsBiTUCAwEAAQ==
—–END RSA PUBLIC KEY—–

Reparem que a primeira chave pública gerada possui o header “—–BEGIN PUBLIC KEY—--“, e agora a chave pública gerada com o argumento “-RSAPublicKey_out” tem um header diferente: —–BEGIN RSA PUBLIC KEY—–

  • Gerando a chave pública no formato PKCS#1 a partir do formato PKCS#8

Se você já tem a chave pública, apenas precisa trocar de PKCS#8 para PKCS#1 com a OpenSSL, basta utilizar:

openssl rsa -pubin -in note-juliow-ssd-public.key -RSAPublicKey_out -out note-juliow-ssd-public_rsa.key

Com isso, agora sim nós temos uma chave pública no formato PKCS#1, que a função RSAModulus() do AdvPL consegue extrair o módulo, basta informar o nome do arquivo adequado “note-juliow-ssd-public_rsa.key”

Por dentro das chaves criptográficas – Expoente

Uma segunda informação importante das chaves criptográficas é o “expoente público”, que está presente  — e igual — em ambas as chaves, privada e pública. Normalmente o expoente utilizado é o número 65537 — por razões de segurança e compatibilidade. Utilizando a função RSAExponent(), podemos obter este número. A sintaxe e parâmetros da função RSAExponent() é igual a RSAModulus(), e o retorno também é uma string AdvPL em formato binário (RAW), contendo bytes de 0 a 255 — que podem ser convertidos para hexadecimal usando a mesma função do exemplo anterior 😀

Conclusão

Por hora, posso concluir que já vimos bastante informações sobre criptografia, chaves criptográficas, OpenSSL e AdvPL. Mas posso afirmar que ainda temos mais conteúdo a frente 😀

Espero que estas informações lhes sejam úteis, e lhes desejo novamente TERABYTES DE SUCESSO !!!!

Referências

 

Criptografia em AdvPL – Parte 13

Introdução

No post anterior (Criptografia em AdvPL – Parte 12), vimos um pouco mais sobre os certificados digitais, e as funções do AdvPL de manipulação / conversão de certificados e chaves. Agora,  finalmente, vamos assinar alguma coisa e ver como isso funciona ! Para ver tudo o que já foi publicado nessa série de posts, acesse o link Criptografia e Segurança.

Assinar digitalmente

Como vimos anteriormente de forma conceitual, a mecânica da criptografia assimétrica, baseada no par de chaves privada/pública, permite somente a quem tem a chave privada codificar um conteúdo, e qualquer um que tenha a chave púbica compatível — gerada a partir daquela chave privada — consegue decodificar um conteúdo.

O objetivo principal da assinatura digital não é codificar o conteúdo em si, mas sim gerar uma informação adicional baseada neste conteúdo, que chamamos de “assinatura”, e um terceiro que receber este conteúdo e a assinatura correspondente, possa afirmar que a assinatura foi feita realmente pela entidade em questão, e que o conteúdo que acompanha a assinatura não foi alterado.

Essa é a funcionalidade básica, mas existem mais variações e extensões, que veremos ao longo dos próximos exemplos.

Primeiro exemplo prático entre duas aplicações

Imaginem que eu desenvolvi hipoteticamente um mecanismo de distribuição de documentos, imagens , qualquer coisa, onde meus clientes precisam ter certeza que fui “eu mesmo” que gerei o documento para eles, e que esse documento não foi violado ou alterado por nenhuma etapa até ele chegar aos meus clientes. O conteúdo do documento em si não é sigiloso, eu não preciso codificar o documento.

Eu tenho uma chave privada, de minha criação e propriedade. Com ela eu sou capaz de codificar informações. Meus clientes vão receber de mim a minha chave púbica, assim eles serão capazes de decodificar qualquer coisa que eu tenha codificado com a minha chave privada. Porém, eu não preciso codificar o documento que eu estou enviando.

O que deve ser feito é calcular um HASH criptográfico do documento que eu estou assinando, usando algum algoritmo suportado — MD5, SHA1, SHA256  — e gerar uma assinatura desse HASH usando a minha chave privada. Então eu envio para os meus clientes a minha chave pública, a imagem e a assinatura que eu gerei, e o cliente tem como verificar se a assinatura enviada bate com o documento, recalculando ele mesmo o HASH do documento que eu mandei, e validando a assinatura enviada com a chave pública.

Assinando um arquivo qualquer em AdvPL

Para exemplificar o mecanismo de assinatura, o programa abaixo pega uma imagem da minha máquina, calcula o SHA1 dessa imagem, e gera uma assinatura usando a minha chave privada.

User Function MYSign()

Local cImageFile := "\imagens\padlock.png"
Local cSignInfo := "\imagens\padlock.sign"
Local cStrImage := ''
Local cHash := ''
Local cSignature := ""
Local nH, nTam
Local cError

// Lê o conteudo da imagem do disco 
nH := fopen(cImageFile)
nTam := fSeek(nH,0,2)
fSeek(nh,0)
fRead(nH,cStrImage,nTam)
fclose(nH)

// Calcula o SHA1 da imagem em formato binário
cHash := SHA1( cStrImage , 1 )

// Gera uma assinatura desse HASH usando a minha chave privada
cSignature := PrivSignRSA( "\siga0984\note-juliow-ssd.key", cHash, 2, "" , @cError )

IF !empty(cError)
  varinfo('PrivSignRSA Error',cError)
  return
Endif

// Salva a assinatura no disco 
nH := fCreate(cSignInfo)
fWrite(nH,cSignature)
fClose(nH)

Return

Executado o programa acima, a assinatura gerada foi salva no arquivo “padlock.sign”. Para gerar a mesma assinatura usando a OpenSSL, o comando executado seria:

openssl dgst -sha1 -sign note-juliow-ssd.key -out padlock.sign padlock.png

Verificando a assinatura

Primeiro, precisamos da chave pública para a verificação. Ela pode ser obtida a partir da chave privada usando o seguinte comando Openssl:

openssl rsa -in note-juliow-ssd.key -pubout > note-juliow-ssd-public.key

E, para verificar a assinatura usando a OpenSSL, usamos a imagem, a chave publica e a assinatura a ser verificada:

openssl dgst -sha1 -verify note-juliow-ssd-public.key -signature padlock.sign padlock.png

Agora vamos ver como fazer isso em AdvPL:

User Function MyVery()

Local cImageFile := "\imagens\padlock.png"
Local cStrImage := ''
Local cSignInfo := "\imagens\padlock.sign"
Local cHash := ''
Local cSignature := ""
Local nH, nTam
Local cError

// Lê o conteudo da imagem do disco 
nH := fopen(cImageFile)
nTam := fSeek(nH,0,2)
fSeek(nh,0)
fRead(nH,cStrImage,nTam)
fclose(nH)

// Calcula o SHA1 da imagem 
cHash := SHA1( cStrImage , 1 )

// Le a assinatura do no disco 
nH := fopen(cSignInfo)
nTam := fSeek(nH,0,2)
fSeek(nh,0)
fRead(nH,@cSignature,nTam)
fclose(nH)

// Verifica se a assinatura bate com o HASH do arquivo 
// usando a minha chave publica
lOk := PrivVeryRSA( "\siga0984\note-juliow-ssd-public.key", cHash, 2, cSignature, @cError )

If lOk
  MsgInfo("Assinatura OK" )
Else
  MsgInfo("Falha de verificação de assinatura",cError )
Endif
Return

Observações muito importantes

  • O HASH criptográfico calculado a partir do dado original deve ser gerado em um formato de string binária, e não em string hexadecimal.
  • As chamadas das funções PrivSignRSA() e PrivVeryRSA() devem ser feitas informando no terceiro parâmetro qual foi o algoritmo de HASH utilizado sobre a informação.

Conclusão

Por hora já podemos fazer coisas bem interessantes, no próximo post vamos ver outras duas funções de assinatura e verificação de assinatura disponíveis no AdvPL — EVPPrivSign e EVPPrivVery, e as diferenças delas para as funções vistas agora. Quer saber um pouco mais sobre como a assinatura funciona por dentro ? Consulte o link de referência “RSA sign and verify using Openssl : Behind the scene”

Agradeço novamente a audiência, e desejo a todos TERABYTES DE SUCESSO !!!

Referências

 

View at Medium.com

Criptografia em AdvPL – Parte 12

Introdução

No post anterior vimos as dicas de ouro de uso da OpenSSL !! Agora, vamos ver um pouco mais sobre os certificados digitais, e as funções do AdvPL de manipulação / conversão de certificados e chaves. Para ver tudo o que já foi publicado nessa série de posts, acesse o link Criptografia e Segurança.

Funções AdvPL para manipulação de Certificados Digitais

No Post 01, vimos uma lista de funções do AdvPL para manipulação de certificados digitais e chaves criptográficas. O objetivo desse grupo de funções é obter algumas informações dos certificados, e realizar a conversão de certificados e chaves de diversos formatos para o formato PEM — usado e suportado pelo TOTVS Application Server e seus componentes.

Função AdvPL PEMInfo()

Documentada no TDN no link http://tdn.totvs.com/display/tec/PEMInfo, essa função permite recuperar algumas informações de um certificado digital armazenado no formado codificado em Base64  (formato PEM/CRT), como a versão do certificado, validade (de-até), emissor, destinatário ou assunto, número serial e Thumbprint ou Fingerprint do certificado (representados em Base64 e hexadecimal). Vamos ver o que ela retorna quando executamos um fonte de testes que abre aquele certificado digital que geramos no Post 06 usando o fonte abaixo:

User Function PemInfo()
Local nI,nJ
Local cFile := '\certificates\note-juliow-ssd.cer'
Local aRet
Conout('Arquivo ......... '+cFile)
aRet := PemInfo(cFile)
Conout('Certificados .... '+cValToChar(len(aRet)))
For nI := 1 to len(aRet)
  Conout('Certificado ['+cValToChar(nI)+']')
  For nJ := 1 to len(aRet[nI])
    conout('['+cValToChar(nJ)+'] '+cValToChar(aRet[nI][nJ]))
  Next 
Next
Return

Antes de executar este código, crie uma pasta chamada “certificates” a partir do rootpath do ambiente, e copie o certificado a ser verificado para dentro dela. Não precisa copiar a chave (key), apenas o certificado. Ao executar o programa usando o certificado gerado anteriormente, o resultado no log de console foi:

Arquivo ......... \certificates\note-juliow-ssd.cer
Certificados .... 1
Certificado [1]
[1] 2
[2] /C=BR/ST=SP/L=Sao Paulo/O=Tudo em AdvPL/CN=note-juliow-ssd
[3] /C=BR/ST=SP/L=Sao Paulo/O=Tudo em AdvPL/CN=note-juliow-ssd
[4] 190816000619Z
[5] 200815000619Z
[6] 540424256993644162400613528322498278498171836889
[7] UVSmBFw2nXziHOJ2wivsBfqRjwg=
[8] 5154a6045c369d7ce21ce276c22bec05fa918f08

Um arquivo pode conter mais de um certificado. Logo, o array retornado sempre é multi-dimensional, onde cada elemento contém um array com 8 propriedades do certificado. No nosso caso, o arquivo contém apenas um certificado. Cada elemento retornado no array indica uma propriedade do certificado:

Índice

Tipo

Dado

1 N Versão (0=Versão 1, 1=Versão 2, 2=Versão 3)
2 C Destinatário (Subject)
3 C Emissor (Issuer)
4 C Data de Validade Inicial
5 C Data de Validade Final
6 C Número serial
7 C Fingerprint/Thumbprint (Base64)
8 C Fingerprint/Thumbprint (Hexadecimal)

Observações

  • As datas de validade inicial e final são retornadas no formado “AAMMDDhhmmssZ” (ano,mes,dia,hora,minuto e segundo, todos com 2 dígitos e o sufixo “Z”, que identifica uma hora universal (GMT).
  • O número serial (índice 5) parece estar sendo retornado com um valor decimal.
  • Os valores do Fingerprint/ThumbPrint são calculados para o certificado — usando SHA1 por default — e retornados em duas formas: Hexadecimal e Base64. Caso seja necessário retornar esta informação usando outro algoritmo de hash, basta especificar o algoritmo desejado no terceiro parâmetro da função.

Usando a OpenSSL

Podemos utilizar o comando abaixo da OpenSSL para ler as informações do certificado:

openssl x509 -in note-juliow-ssd.cer -noout -text -fingerprint

E com ele obtemos o resultado abaixo:

Version: 3 (0x2)
Serial Number:
5e:a9:76:38:db:c0:3c:5e:cf:f6:8b:e0:cf:7c:b8:5c:ad:87:59:d9
Issuer: C = BR, ST = SP, L = Sao Paulo, O = Tudo em AdvPL, CN = note-juliow-ssd
Validity
Not Before: Aug 16 00:06:19 2019 GMT
Not After : Aug 15 00:06:19 2020 GMT
Subject: C = BR, ST = SP, L = Sao Paulo, O = Tudo em AdvPL, CN = note-juliow-ssd
SHA1 Fingerprint=51:54:A6:04:5C:36:9D:7C:E2:1C:E2:76:C2:2B:EC:05:FA:91:8F:08

Função AdvPL WriteRSAPK()

Documentada no TDN no link http://tdn.totvs.com/display/tec/WriteRSAPK, a função WriteRSAPK() foi criada para permitir a conversão de uma chave privada no formato DER para PEM, bastando informar onde está o arquivo com a chave privada de origem, e onde deve ser gerada a chave de destino.

Uma chave privada ou mesmo um certificado digital são salvos em disco normalmente usando dois formatos:

  • Arquivo texto codificado em Base64 — formato PEM
  • Arquivo ASCII binário — Formato DER

Os formatos PEM são usados por exemplo em servidores Apache e similares, enquanto o formato DER é usado em aplicações Java. O conteúdo da chave privada é o mesmo, o que muda é a forma de representação da chave do arquivo. Como os formatos de certificados e chaves no TOTVS Application Server são os do Apache (PEM), todas as demais funções de conversão de certificados e chaves do AdvPL até o momento convertem informações, certificados e chaves de outros formatos ( PKCS, PFX, DER ) para PEM.

Funções de suporte ao formato PFX/PKCS12

O formato PFX (ou PKCS12) — usado pelo Windows / IIS por exemplo — é um container que permite encapsular — dentro do mesmo aquivo — por exemplo um ou mais certificados digitais, certificado(s) da cadeia de autenticação, chaves privadas e outros. Para facilitar a extração e conversão destas informações de um arquivo no formato PFX para PEM, o AdvPL disponibiliza as seguintes funções:

E, adicionalmente, para obter a lista de informações que estão dentro de um determinado arquivo PFX, temos também a função PFXInfo – http://tdn.totvs.com/display/tec/PFXInfo. Esta função retorna apenas informações básicas sobre o certificado principal e o(s) certificados da Autoridade Certificadora — quando presentes — do arquivo, como por exemplo a verão do certificado, emissor, destinatário e datas de validade inicial e final.

Todas as funções acima têm em comum o arquivo PFX a ser avaliado e um parâmetro opcional de senha, que deve ser utilizado quando o arquivo PFX estiver protegido por senha. E, claro, a função somente obterá sucesso se o arquivo PFX utilizado tiver a informação que será extraída 😀

Formatos PKCS7 (P7B) e PKCS8

Além dos formatos já vistos, ainda temos o PKCS e PKCS8, que podem ser usados para guardar uma chave privada. Para extrair a chave privadas destes formatos para o formato PEM em AdvPL, podemos usar as funções abaixo:

Conclusão

Agora que já vimos hash criptográfico, uso de certificados da infra-estrutura do TOTVS Application Server — HTTPS e conexão segura com SmartClient, nos próximos posts serão abordadas funcionalidades de assinatura digital usando o AdvPL 😀

Agradeço novamente a audiência e lhes desejo TERABYTES DE SUCESSO !!!

Referências

 

Criptografia em AdvPL – Parte 11

Introdução

Até agora vimos alguns exemplos de uso da OpenSSL para realizar operações com certificados e chaves. Agora, vamos dar uma repassada nas funcionalidades da ferramenta, e ver algumas considerações e dicas de utilização 😀 Para acessar o índice com todas as publicações sobre o tema Criptografia em AdvPL, acesse o link Criptografia e Segurança

OpenSSL

Em posts anteriores, vimos como instalar uma versão da OpenSSL já “pronta” para Windows, e utilizamos vários comandos para os exemplos de certificados e chaves. Mas não chegamos nem perto de ver tudo o que ela pode fazer. Meu objetivo não é dar um curso de OpenSSL, mas sim compartilhar as fontes de busca que eu usei, e as conclusões que eu cheguei nesta primeira semana de uso da ferramenta.

OpenSSL tem muito mais do que apenas a linha de comandos

Quando instalamos por exemplo a OpenSSL completa no Windows, não temos apenas a linha de comandos, mas também os arquivos necessários para você criar por exemplo um projeto em C++ usando um compilador ou ferramenta de sua preferência para usar as funções da LIB OPENSSL, que já vêm com versões prontas para uso, com os respectivos arquivos de include — para usar as funções e os tipos de dados declarados na biblioteca.

A aplicação via linha de comandos faz muita coisa

Em todos os exemplos até o momento, usamos as chamadas da OpenSSL para realizar tarefas específicas através de argumentos. Existe uma relação enorme de funcionalidades, e também existe o modo “interativo”, onde executamos a openssl sem nenhum parâmetro, e ela nos oferece um interpretador de comandos para realizar diversas operações interativas, como por exemplo estabelecer uma conexão segura com um provedor de emails (POP, IMAP, SMPT), testar a aderência de um certificado em  uma conexão segura com um Web Service usando HTTPS com autenticação mútua, etc…

Pequeno resumo de operações

Quando executamos o comando “openssl help“, temos uma ideia de tudo o que dá pra fazer …

Standard commands
asn1parse ca ciphers cms
crl crl2pkcs7 dgst dhparam
dsa dsaparam ec ecparam
enc engine errstr gendsa
genpkey genrsa help list
nseq ocsp passwd pkcs12
pkcs7 pkcs8 pkey pkeyparam
pkeyutl prime rand rehash
req rsa rsautl s_client
s_server s_time sess_id smime
speed spkac srp storeutl
ts verify version x509

Message Digest commands (see the `dgst' command for more details)
blake2b512 blake2s256 gost md4
md5 mdc2 rmd160 sha1
sha224 sha256 sha3-224 sha3-256
sha3-384 sha3-512 sha384 sha512
sha512-224 sha512-256 shake128 shake256
sm3

Cipher commands (see the `enc' command for more details)
aes-128-cbc aes-128-ecb aes-192-cbc aes-192-ecb
aes-256-cbc aes-256-ecb aria-128-cbc aria-128-cfb
aria-128-cfb1 aria-128-cfb8 aria-128-ctr aria-128-ecb
aria-128-ofb aria-192-cbc aria-192-cfb aria-192-cfb1
aria-192-cfb8 aria-192-ctr aria-192-ecb aria-192-ofb
aria-256-cbc aria-256-cfb aria-256-cfb1 aria-256-cfb8
aria-256-ctr aria-256-ecb aria-256-ofb base64
bf bf-cbc bf-cfb bf-ecb
bf-ofb camellia-128-cbc camellia-128-ecb camellia-192-cbc
camellia-192-ecb camellia-256-cbc camellia-256-ecb cast
cast-cbc cast5-cbc cast5-cfb cast5-ecb
cast5-ofb des des-cbc des-cfb
des-ecb des-ede des-ede-cbc des-ede-cfb
des-ede-ofb des-ede3 des-ede3-cbc des-ede3-cfb
des-ede3-ofb des-ofb des3 desx
idea idea-cbc idea-cfb idea-ecb
idea-ofb rc2 rc2-40-cbc rc2-64-cbc
rc2-cbc rc2-cfb rc2-ecb rc2-ofb
rc4 rc4-40 seed seed-cbc
seed-cfb seed-ecb seed-ofb sm4-cbc
sm4-cfb sm4-ctr sm4-ecb sm4-ofb

Logo de cara são pelo menos 48 comandos, cada um deles abre um leque de opções. Para ver por exemplo o que pode fazer o comando x509 ou qualquer outro comando, use a sintaxe openssl <comando> -help, por exemplo:

openssl x509 -help
Usage: x509 [options]
Valid options are:
-help Display this summary
-inform format Input format - default PEM (one of DER or PEM)
-in infile Input file - default stdin
-outform format Output format - default PEM (one of DER or PEM)
-out outfile Output file - default stdout
-keyform PEM|DER Private key format - default PEM
-passin val Private key password/pass-phrase source
-serial Print serial number value
-subject_hash Print subject hash value
-issuer_hash Print issuer hash value
-hash Synonym for -subject_hash
-subject Print subject DN
-issuer Print issuer DN
-email Print email address(es)
-startdate Set notBefore field
-enddate Set notAfter field
-purpose Print out certificate purposes
-dates Both Before and After dates
-modulus Print the RSA key modulus
-pubkey Output the public key
-fingerprint Print the certificate fingerprint
-alias Output certificate alias
-noout No output, just status
-nocert No certificate output
-ocspid Print OCSP hash values for the subject name and public key
-ocsp_uri Print OCSP Responder URL(s)
-trustout Output a trusted certificate
-clrtrust Clear all trusted purposes
-clrext Clear all certificate extensions
-addtrust val Trust certificate for a given purpose
-addreject val Reject certificate for a given purpose
-setalias val Set certificate alias
-days int How long till expiry of a signed certificate - def 30 days
-checkend intmax Check whether the cert expires in the next arg seconds
Exit 1 if so, 0 if not
-signkey infile Self sign cert with arg
-x509toreq Output a certification request object
-req Input is a certificate request, sign and output
-CA infile Set the CA certificate, must be PEM format
-CAkey val The CA key, must be PEM format; if not in CAfile
-CAcreateserial Create serial number file if it does not exist
-CAserial val Serial file
-set_serial val Serial number to use
-text Print the certificate in text form
-ext val Print various X509V3 extensions
-C Print out C code forms
-extfile infile File with X509V3 extensions to add
-rand val Load the file(s) into the random number generator
-writerand outfile Write random data to the specified file
-extensions val Section from config file to use
-nameopt val Various certificate name options
-certopt val Various certificate text options
-checkhost val Check certificate matches host
-checkemail val Check certificate matches email
-checkip val Check certificate matches ipaddr
-CAform PEM|DER CA format - default PEM
-CAkeyform format CA key format - default PEM
-sigopt val Signature parameter in n:v form
-force_pubkey infile Force the Key to put inside certificate
-next_serial Increment current certificate serial number
-clrreject Clears all the prohibited or rejected uses of the certificate
-badsig Corrupt last byte of certificate signature (for test)
-* Any supported digest
-subject_hash_old Print old-style (MD5) issuer hash value
-issuer_hash_old Print old-style (MD5) subject hash value
-engine val Use engine, possibly a hardware device
-preserve_dates preserve existing dates when signing

Quer ver TUDO o que pode ser feito com linhas de comando na OPENSS ? Acesse a documentação oficial no Acesse o link https://wiki.openssl.org/index.php/Command_Line_Utilities, ele começa com um overview e alguns exemplos mais comuns, e no final da página, um índice para a documentação completa de cada comando disponível. Lembre-se de verificar qual a versão da OpenSSL que você está usando ( use o comando openssl version ), pois alguns parâmetros ou propriedades podem ter sido descontinuados ou implementados apenas em uma versão superior

openssl version
OpenSSL 1.1.1c 28 May 2019

Dica de Ouro 01

Como as especificações de segurança, certificados, chaves e afins são imensas, embora muita coisa possa ser feita com diversos parâmetros em linhas de comando, existem configurações default para várias operações pré-definidas no arquivo de configuração da openssl — normalmente um arquivo chamado  “openssl.cfg” ou “openssl.cnf”, dependendo da definição ou ausência da variável de ambiente OPENSSL_CONF que aponte para um arquivo default de configuração.

Quando você vai realizar determinadas operações, como emissão de certificados, assinaturas, chaves e afins para contextos diferentes, é muito interessante você criar seus arquivos de configuração, alterá-los e acrescentar as demais definições que você precisa dentro deles. Boa parte dos comandos que dependem de configuração aceitam o parâmetro “-config <configfile>“, onde podemos informar qual arquivo de configurações que deve ser utilizado. Isso diminui muito a necessidade de parâmetros adicionais nos comandos, mas ainda assim permite especificar parâmetros adicionais que, quando informados, têm precedência sobre os parâmetros de linha.

Dica de Ouro 02

Muitos parâmetros em linha de comando são comuns a muitos comandos, como -in , -out , -text, -noout — usados respectivamente para especificar um ou mais arquivos de entrada, um arquivo de saída, um formato de sai da em modo texto e inibir a saída de um resultado no console, por exemplo.

 openssl pkey -in private-key.pem -text

Usamos o comando pkey, para lidar com chaves privadas, especificamos que vamos usar como entrada (in) o arquivo private-key.pem, e queremos o resultado em formato texto. Ao executar este comando em uma chave privada previamente gerada, o resultado em tela vai a chave privada usada como entrada, e depois todos os dados da chave. Se quisermos uma saída onde a chave de entrada não seja mostrada, usamos o parâmetro “-noout”.

Dica de Ouro 03

Meu chapa, OPENSSL não é um projeto que nasceu ontem, têm documentação a rodo na internet. Quem já passou por algum apuro pra tentar fazer algo funcionar normalmente compartilha o embrolho e a resposta. Pergunte para o “Mestre Google”, que ele vai encontrar ou te levar para perto de onde está a resposta. Stack Overflow, blogs, inúmeros how-to estão disponíveis. Tudo o que eu compartilhei com vocês nesses últimos posts sobre criptografia e OpenSSL eu aprendi com pesquisas de múltiplas fontes e testes de prova de conceito.

A grande sacada é você não tentar entender tudo de uma vez, o “tudo” é grande demais, a Wikipedia tem páginas e mais páginas sobre todos esses assuntos. Não se limite a pesquisar na Wiki em Português, normalmente os conteúdos são bem mais superficiais do que o mesmo assunto na Wiki em inglês. Quando eu comecei a apender Clipper, literalmente no século passado, o guia de funções e comandos era inteiro em Inglês, e a Internet ainda não tinha chego por aqui …. Logo, meu dicionário de inglês-português era item permanente na minha mesa. Hoje você tem Internet e o Google Translator, use-os !!!

Se uma especificação completa parece complicada, encontre uma fonte de informação menos abrangente, ou que transmita o conceito. A infraestrutura de chaves criptográficas é enorme, mas quando você entende um minimo sobre as partes básicas envolvidas, o resto são propriedades e derivações sobre a mesma base. Toda a linguagem de programação tem IF e LOOP, o que muda é a sintaxe.

Dica de Ouro 04

Qualquer conhecimento é melhor assimilado se você não apenas lê, mas USA. Isso é válido pra tudo, não só pra OpenSSL e criptografia. Quer aprender a programar ? Idealize um programa simples e faça-o. Cada parte do programa vai exigir que você pesquise como fazer, e somente o uso disso vai te trazer experiência, não apenas conhecimento.

Conclusão

Com esta série de posts, eu acho que já temos uma introdução bem “consistente” sobre esse assunto, a partir de agora vamos ver nos próximos posts o que mais temos no AdvPL onde isso pode ser usado, e como usar !!!

Agradeço a todos pela audiência, e lhes desejo TERABYTES DE SUCESSO !!!

Referências

 

Criptografia em AdvPL – Parte 10

Introdução

No post anterior, vimos em mais detalhes o objetivo e uso das chaves públicas, e como funciona um Handshake de conexão segura para HTTPS. Agora, vamos ver como gerar um certificado digital a partir de outro certificado, usando o certificado “pai” para autenticar o certificado “filho”, e usar isso no nosso exemplo de HTTPS 😀

Posts anteriores

Lembrando do primeiro teste com HTTPS

No Post 06 tem a receita de bolo pra gerar um certificado auto-assinado e usá-lo no TOTVS Application Server para prover acesso via HTTPS. Em resumo, trata-se de um certificado auto-assinado com extensões v3, para ser usado no servidor HTTPS em um determinado host, e para o navegador aceitar o certificado, ele precisava ser instalado na máquina cliente como um Trusted Root Certificate.

Certificados com cadeia de autenticação

Agora, vamos fazer um mecanismo um pouco mais elegante: Criar um certificado raiz auto-assinado, e criar um outro certificado para o HTTPS, com todos os dados necessários, porém assinado pelo primeiro certificado. E isso permite eu praticamente fazer o papel de uma autoridade certificadora — não oficial, claro.

Imagine que eu vou fazer o papel fictício de Autoridade Certificadora, e você quer criar um site seu, usando um certificado seu, mas quer que ele seja autenticado pelo meu certificado. Eu, como autoridade certificadora fictícia, tenho um certificado auto-assinado que eu uso como “raiz”, a base de tudo, com uma chave privada minha atrelada a este certificado.

Então, primeiro você cria a sua chave privada para ser usada pelo seu certificado. Porém, você não vai criar o certificado propriamente dito, você vai criar uma CSR (Certificate Signing Request), ou requisição de assinatura de certificado, com tudo o que você quer no seu certificado, e vai mandar ela para eu assinar com o meu certificado e com a minha chave. Eu vou criar o seu certificado para você, usando os dados que você forneceu na requisição de assinatura, e vou assinar o seu certificado com o meu.

Repare que eu tenho uma chave privada do meu certificado, e você vai usar a sua chave privada no seu certificado, mas em nenhum momento nem eu e nem você podemos tre acesso as chaves privadas um do outro. Neste processo as chaves públicas são intrinsecamente utilizadas: Quando eu receber a sua requisição de assinatura, a requisição em si traz junto a sua chave pública embutida, e todos os dados que você quer no seu certificado. Eu crio e assino o seu certificado, para que ele possa ser autenticado pelo meu certificado, mas o seu certificado ainda assim vai usar a sua chave privada no seu ambiente.

Quando você colocar o seu site no ar, você vai usar o seu certificado e a sua chave privada nas configurações do HTTPS, porém você não vai precisar pedir para os seus clientes — que vão acessar o seu site — instalar o seu certificado na maquina deles, você pede para eles instalarem o meu certificado — que assinou o seu — como Trusted Root Certificate. 😀 Assim, a máquina que tiver o meu certificado raiz não vai ter a minha chave privada, e o meu certificado será usado para verificar a assinatura do seu certificado quando o cliente acessar o seu site 😀

Fazendo a mágica

Eu, atuando como Autoridade Certificadora, crio a minha chave privada e o meu certificado auto-assinado:

-- Criando chave privada protegida por senha 
openssl genrsa -des3 -out rootCA.key 4096

-- Criando o meu certificado raiz para ser uma "autoridade certificadora"
openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 1024 -out rootCA.crt 

O primeiro comando vai perguntar a senha para uso da chave privada, e na criação do meu certificado raiz eu coloco informações que me identificam.

Agora você vai criar a sua chave privada e uma requisição de assinatura para o seu certificado:

-- Voce cria a sua chave privada
openssl genrsa -out mydomain.com.key 2048

-- e cria uma requisição de assinatura
openssl req -new -key mydomain.com.key -out mydomain.com.csr -subj "/C=BR/ST=SP/L=Sao Paulo/O=Testes INC/CN=mydomain.com" 

A sua requisição de assinatura vai estar gravada no arquivo “mydomain.com.csr“, e você manda esse aquivo para eu assinar com o meu certificado. Eu vou assinar seu certificado com o seguinte comando:

openssl x509 -req -in mydomain.com.csr -extfile v3.ext -CA rootCA.crt -CAkey rootCA.key -CAcreateserial -out mydomain.com.crt

Para assinar o seu certificado, eu tive que criar um arquivo a mais, no exemplo acima chamado de “v3.ext”, onde eu vou colocar algumas extensões no seu certificado.

basicConstraints = CA:FALSE
keyUsage=digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectKeyIdentifier = hash
subjectAltName=DNS:mydomain.com

No final das contas, o seu certificado vai ser gerado no arquivo “mydomain.com.crt“, e eu mando esse arquivo pra você, e mando também o meu certificado “rootCA.crt“.

Agora você tem a sua chave privada “mydomain.com.key”  e o seu certificado “mydomain.com.crt“, e você configura o seu servidor HTTPS para usá-los.

[sslconfigure]
CertificateServer=c:\Protheus12LG\certificates\mydomain.com.crt
KeyServer=c:\Protheus12LG\certificates\mydomain.com.key

E, você ou qualquer outra pessoa que acesse o seu site, deve apenas instalar o meu certificado na máquina cliente como “Trusted Root Certificate“. Dessa forma, quando um navegador abrir o seu site, ele vai encontrar o seu certificado, e para validar a relação de confiança desse certificado, ele procura um certificado raiz confiável, e encontra o meu certificado — que é capaz de dizer que o seu certificado foi assinado por mim 😀

Se, amanhã você colocar outro site no ar, você repete o processo de criação de chaves e requisição de assinatura, e eu crio e assino o seu novo certificado, e todas as pessoas que já instalaram o meu certificado nas máquinas delas para acessar o seu site, não precisam mais instalar nada, pois o meu certificado raiz é capaz de autenticar qualquer certificado que eu tenha assinado com ele 😀

Estendendo a cadeia de autenticação ou confiança

Por hora a cadeia de autenticação desse exemplo possui apenas o certificado raiz, e cada certificado assinado por ela confia no raiz. Se, ao invés de você me pedir para assinar um certificado de uso final, você crie o seu certificado raiz e eu assine esse certificado, você mesmo pode emitir certificados para terceiros, assinados com o seu certificado raiz. Com isso, quando um navegador usar um certificado que você emitiu, ele vai procurar o seu certificado raiz — que não necessariamente precisa ser um “Trusted Root”, mas sim um “Trusted CA” — e quando ele encontrar o seu certificado raiz, ele verifica que ele foi emitido por mim, e confia nele desde que o meu certificado raiz seja um “Trusted Root” 😀

Eu sei, logo de cara é um pouco complicado, mas esse mecanismo — quando bem configurado e utilizado — provê um mecanismo de confiança muito seguro. Vamos ver agora alguns exemplos do mundo real.

Assinatura digital de aplicativos

Quando você vai instalar um programa qualquer,  o sistema operacional da sua máquina verifica se o seu programa tem uma assinatura digital que indica quem é o fornecedor desse programa. A cadeia de autenticação é praticamente a mesma, porém você tem um tipo diferente de certificado, com outras propriedades e extensões. Na instalação do programa, ao verificar o certificado usado para a assinatura, caso a assinatura não possa ser verificada, o sistema operacional pergunta se você confia nessa assinatura, e você aceita o risco de instalar o programa. E, se você confia naquela assinatura, você pode ainda declarar que “sempre confia” naquela assinatura, e quando você instalar outro programa assinado com este certificado, o sistema operacional não vai perguntar novamente se você confia nele, e vai deixar o programa ser executado.

Agora, já pensou se alguém consegue assinar um aplicativo malicioso, com um vírus ou um Trojan Horse, copiando a assinatura da Microsoft ? Ou da Symantec ? Se a assinatura for determinada erroneamente como confiável, o estrago é inimaginável e transparente, o programa faz o que quiser com a sua maquina !!! Por isso a infraestrutura de segurança é desenhada para não ser quebrada, senão a “vaca vai pro brejo” !!!!

Conclusão

Já vimos bastante coisa até o momento, mas ainda têm bastante a ser visto. Toda essa introdução com os respectivos exemplos serve para a gente entender o tamanho do mecanismo e seus componentes. A partir de agora, todas as demais camadas e mecanismos são baseados em tudo o que foi explicado até aqui, isso serve de “base” para tudo o que ainda vamos ver pela frente !!!

Agradeço novamente pela audiência, e lhes desejo TERABYTES DE SUCESSO !!! 

Referências