Utilitário inglês de plataforma cruzada para exibição de certificados qualificados russos x509

imagem Hoje, o uso de certificados digitais X509 v.3 tornou-se comum. Mais e mais pessoas as usam para acessar o site do Serviço de Estado, Serviço de Impostos Federais, licitação eletrônica, etc. E mais e mais pessoas querem saber o que há neste "baú" chamado certificado. E se o certificado é análogo a um passaporte, como pode ser lido / visualizado. Sim, nos sistemas operacionais, existem vários utilitários para visualização. Mas eles pouco darão ao cidadão comum. Tomemos, por exemplo, o utilitário gcr-viewer, que, de fato, é a ferramenta padrão para visualização em sistemas Linux e, portanto, em sistemas operacionais domésticos :



Visualizador padrão


O utilitário é bem feito, conveniente. Em geral, destina-se a um utilitário universal para exibir arquivos que contêm dados em vários formatos criptográficos (certificados, solicitações, assinaturas eletrônicas / PKCS # 7, contêineres protegidos PKCS # 12, etc.). Infelizmente, porém, ele foi projetado para criptografia ocidental e não leva em consideração os que foram inseridos no seu país. E se você observar a captura de tela, quando as informações sobre o titular do certificado forem exibidas, caracteres incompreensíveis aparecerão. À esquerda estão os próprios oides, e à direita, na 16ª forma, a estrutura asn1 com seus valores. Nesse caso, são OGRN (1.2.643.100.1), SNILS (1.2.643.100.3) e TIN (1.2.643.3.131.1.1). E é assim que um cidadão comum deve se certificar de que esses são seus dados. Não pense que isso é apenas no Linux, é um recurso comum de qualquer visualizador de certificados. E se você olhar além, tudo se torna incompreensível:



Algumas extensões, identificadores e valores são exibidos. Nesse caso, oid om 1.2.643.100.111 oculta o nome do CIPF, que foi usado pelo usuário para gerar o par de chaves, a chave privada da qual foi usada para assinar a solicitação de certificado e a chave pública da qual está o certificado:



E aqui, pouco é entendido pelo detentor do certificado. Ele nem entende qual algoritmo foi usado para gerar a chave, GOST R 34.10-2001 ou GOST R 34.10-2012 e com qual tamanho de chave.

Você pode continuar dando exemplos. Por exemplo, se a validade do certificado estiver clara, onde está a chave?

Há mais duas perguntas para as quais os detentores de certificados gostariam de ter uma resposta: onde posso obter uma cadeia de certificados raiz (ou melhor ainda, obter um) e uma pergunta semelhante na lista de certificados revogados.

E, finalmente, eu gostaria de ter um utilitário universal que leve em consideração os recursos da PKI / PKI russa, que é verdadeiramente multiplataforma e roda em sistemas operacionais domésticos e não domésticos . O que desenvolver? É claro que em uma linguagem de script, mesmo que seja por causa de sua natureza de plataforma cruzada.

Então lembrei que a bela linguagem de script Tcl (Tool Command Language) havia recentemente comemorado seu 30º aniversário . É um prazer programar isso. Possui um grande número de extensões (pacotes) que permitem quase tudo. Portanto, para trabalhar com estruturas ASN, existe um pacote asn. Além disso, para trabalhar com certificados (estamos interessados ​​em analisá-los nesse caso), existe um pacote pki. E para o desenvolvimento de uma interface gráfica, existe um pacote Tk.

Tudo o mesmo pode ser dito sobre Pyton com Tkinter, sobre perl e sobre ruby. Todos podem escolher de acordo com o seu gosto. Paramos em um monte de Tcl / Tk.

Vamos emprestar o design gráfico para o utilitário do utilitário gcr-viewer. E mais um requisito.

Como o Habr tinha uma versão em inglês , eu queria que o utilitário tivesse interfaces diferentes (russo / inglês). Mas esse não é o principal motivo. Mais importante, mais e mais cidadãos do mundo ocidental estão se tornando cidadãos da Federação Russa, por exemplo, o mundialmente famoso ator Depardieu. Eles podem objetar: ele é um francês. Mas também sou tradutor militar de francês:



Portanto, é fácil adicionar uma interface em francês. Mas acho que Depardieu não tem problemas com o idioma inglês. Por outro lado, nosso país é multinacional e seria muito bom se o software e o SO doméstico tivessem pelo menos várias interfaces nacionais.
Correndo um pouco à frente, foi isso que aconteceu:



Convidamos um tradutor


Então, vamos começar com o "tradutor". Na imagem, ele está escondido sob a bandeira nacional. O principal requisito para um tradutor é a sincronização da tradução, ou seja, a capacidade de mudar para outro idioma a qualquer momento. As funções do tradutor em Tcl / Tk são executadas pelo pacote msgcat:

package require msgcat 

Para definir o idioma atual, use o seguinte comando:

 msgcat::mclocale ru 

O vocabulário do "tradutor" é armazenado no arquivo ru.msg da seguinte maneira:

 #  msgcat::mcset      #     mcset namespace import -force msgcat::mcset #     mcset ru "Language" "" … 

A seguir, o texto do teste
roteiro com tradutor:
 #!/usr/bin/wish -f #  msgcat package require msgcat #   ru msgcat::mclocale ru #  ::msgcat::mc      #     mc namespace import msgcat::mc #    [msgcat::mclocale].msg. #       . msgcat::mcload [file join [file dirname [info script]]] #  image create photo rf_32x21_f -file rf_32x21.png image create photo gb_32x21_f -file gb_32x21.png #,      label .lab -text "[mc Language]: " -relief flat -bd 0 –bg snow -anchor sw -width 10 button .but_lang -image rf_32x21_f -command ::changelang -relief flat -bd 0 pack .lab -side left -pady {2 0} pack .but_lang -side left #      proc ::changelang {} { #     #    if {[msgcat::mclocale] == "ru"} { msgcat::mclocale en .but_lang configure -image gb_32x21_f } else { msgcat::mclocale ru .but_lang configure -image rf_32x21_f } #  .lab configure -text "[mc Language]: " } 


Nesse script, o procedimento :: changelang atua como tradutor, chamado quando o botão .but_lang com o sinalizador é pressionado.

Se você executar este script, verá claramente como o tradutor funciona:



Obter a chave pública


Agora que decidimos um tradutor, vamos prosseguir com a análise do certificado. Para fazer isso, precisamos do pacote pki:

 package require pki). 

O pacote pki foi projetado para funcionar com chaves e certificados do algoritmo RSA. Se o certificado (proc :: pki :: x509 :: parse_cert) foi criado com um tipo diferente de chave, não receberemos informações sobre essa chave:

 # Handle RSA public keys by extracting N and E switch -- $ret(pubkey_algo) { "rsaEncryption" { set pubkey [binary format B* $pubkey] binary scan $pubkey H* ret(pubkey) ::asn::asnGetSequence pubkey pubkey_parts ::asn::asnGetBigInteger pubkey_parts ret(n) ::asn::asnGetBigInteger pubkey_parts ret(e) set ret(n) [::math::bignum::tostr $ret(n)] set ret(e) [::math::bignum::tostr $ret(e)] set ret(l) [expr {int([::pki::_bits $ret(n)] / 8.0000 + 0.5) * 8}] set ret(type) rsa } } 

Surpreendentemente, o algoritmo de chave pública ainda retorna (ret (pubkey_algo))
A situação é a mesma com a análise da solicitação de certificado (proc :: pki :: pkcs :: parse_csr):

 # Parse public key, based on type switch -- $pubkey_type { "rsaEncryption" { set pubkey [binary format B* $pubkey] ::asn::asnGetSequence pubkey pubkey_parts ::asn::asnGetBigInteger pubkey_parts key(n) ::asn::asnGetBigInteger pubkey_parts key(e) set key(n) [::math::bignum::tostr $key(n)] set key(e) [::math::bignum::tostr $key(e)] set key(l) [expr {2**int(ceil(log([::pki::_bits $key(n)])/log(2)))}] set key(type) rsa } default { return -code error "Unsupported key type: $pubkey_type" } } 

Mas aqui ele até retorna informações sobre o erro. Hoje, porém, além da RSA, por exemplo, estão em uso chaves nas curvas elípticas da UE, incluindo o GOST R 34.10-2012 (o GOST R 34.10-2001 também está disponível por enquanto).

Mas, por padrão, é suficiente retornar a estrutura ASN da chave pública que está no certificado ou solicitação, e o próprio usuário analisará a chave pública, dependendo do tipo de chave. Para fazer isso, basta adicionar a estrutura ASN da chave pública em valores hexadecimais aos valores retornados:

 proc ::pki::x509::parse_cert {cert} { . . . ::asn::asnGetSequence cert subject ::asn::asnGetSequence cert pubkeyinfo #    ASN-  . binary scan $pubkeyinfo H* ret(pubkey_pubkeyinfo) . . . } 

Tudo, nada mais a fazer. Dessa maneira, o procedimento :: pki :: x509 :: parse_cert retorna a maioria das extensões de certificado pelo simples motivo de não saber como analisá-las (por exemplo, subjectSignTool com nossos certificados qualificados), ou seja, dá a critério do usuário.

Por outro lado, o procedimento :: pki :: x509 :: parse_cert retorna um dos resultados de um certificado tbs que contém todas as informações do certificado, exceto sua assinatura (assinatura) e tipo de assinatura (signature_algo):

 #    set fd [open «cert.pem» r] chan configure –translation binary set datacert [read $fd] close $fd #  array set cert_parse [::pki::x509::parse_cert $datacert] # tbs- set cert_tbs_hex $cert_parse(cert) 

Escrevemos o procedimento para extrair informações de chave pública de um certificado tbs:

 proc ::pki::x509::parse_cert_pubkeyinfo {cert_tbs_hex} { array set ret [list] set wholething [binary format H* $cert_tbs_hex] ::asn::asnGetSequence wholething cert ::asn::asnPeekByte cert peek_tag if {$peek_tag != 0x02} { # Version number is optional, if missing assumed to be value of 0 ::asn::asnGetContext cert - asn_version ::asn::asnGetInteger asn_version ret(version) } ::asn::asnGetBigInteger cert ret(serial_number) ::asn::asnGetSequence cert data_signature_algo_seq ::asn::asnGetObjectIdentifier data_signature_algo_seq ret(data_signature_algo) ::asn::asnGetSequence cert issuer ::asn::asnGetSequence cert validity ::asn::asnGetUTCTime validity ret(notBefore) ::asn::asnGetUTCTime validity ret(notAfter) ::asn::asnGetSequence cert subject ::asn::asnGetSequence cert pubkeyinfo #    hex asn-   binary scan $pubkeyinfo H* ret(pubkeyinfo) return $ret(pubkeyinfo) } 

E como estamos interessados ​​na criptografia russa, escreveremos imediatamente o procedimento para analisar a chave pública GOST:

 proc parse_key_gost {pubkeyinfo_hex} { array set ret [list] set pubkeyinfo [binary format H* $pubkeyinfo_hex] ::asn::asnGetSequence pubkeyinfo pubkey_algoid ::asn::asnGetObjectIdentifier pubkey_algoid ret(pubkey_algo) #,   - if {[string first "1 2 643 " $ret(pubkey_algo)] == -1} { return [array get ret] } ::asn::asnGetBitString pubkeyinfo pubkey set pubkey [binary format B* $pubkey] #   binary scan $pubkey H* ret(pubkey) ::asn::asnGetSequence pubkey_algoid pubalgost #OID -  ::asn::asnGetObjectIdentifier pubalgost ret(paramkey) #OID -   ::asn::asnGetObjectIdentifier pubalgost ret(hashkey) #puts "ret(paramkey)=$ret(paramkey)\n" #puts "ret(hashkey)=$ret(hashkey)\n" #parray ret #  :  ,     return [array get ret] } 

Sim, quase perdi: depois de baixar o pacote pki, você precisa adicionar aos oids array :: pki :: oids que caracterizam o GOST e o certificado qualificado ou simplesmente não estão nessa matriz:

 package require pki # oid- set ::pki::oids(1.2.643.100.1) "OGRN" set ::pki::oids(1.2.643.100.5) "OGRNIP" set ::pki::oids(1.2.643.3.131.1.1) "INN" set ::pki::oids(1.2.643.100.3) "SNILS" set ::pki::oids(1.2.643.2.2.19) "GOST R 34.10-2001" set ::pki::oids(1.2.643.7.1.1.1.1) "GOST R 34.10-2012-256" set ::pki::oids(1.2.643.7.1.1.1.2) "GOST R 34.10-2012-512" set ::pki::oids(1.2.643.2.2.3) "GOST R 34.10-2001 with GOST R 34.11-94" set ::pki::oids(1.2.643.7.1.1.3.2) "GOST R 34.10-2012-256 with GOSTR 34.11-2012-256" set ::pki::oids(1.2.643.7.1.1.3.3) "GOST R 34.10-2012-512 with GOSTR 34.11-2012-512" set ::pki::oids(1.2.643.100.113.1) "KC1 Class Sign Tool" set ::pki::oids(1.2.643.100.113.2) "KC2 Class Sign Tool" . . . 

Você também pode reabastecer o vocabulário do tradutor adicionando ao arquivo ru.msg:

 mcset ru "GOST R 34.10-2001" "  34.10-2001" mcset ru "GOST R 34.10-2012-256" "  34.10-2012-256" mcset ru "GOST R 34.10-2012-512" "  34.10-2012-512" mcset ru "GOST R 34.10-2001 with GOST R 34.11-94" "  34.10-2001    34.11-94" mcset ru "GOST R 34.10-2012-256 with GOSTR 34.11-2012-256" "  34.10-2012-256    34.11-2012-256" mcset ru "GOST R 34.10-2012-512 with GOSTR 34.11-2012-512" "  34.10-2012-512    34.11-2012-512" . . . 
:


Cadeia de certificados raiz e lista de revogação de certificados


Como obter uma cadeia de certificados raiz já foi discutido anteriormente. Por analogia, um procedimento é escrito para obter uma lista de certificados COS / CRL revogados. O código fonte do utilitário e suas distribuições para Linux, OS X (macOS) e MS Windows podem ser encontrados


No código-fonte, você pode encontrar todos os procedimentos para analisar extensões de certificado.
Para os oponentes de Tk (Tcl / Tk, Python / Tkinter, etc.), proponho encontrar, como se costuma dizer, 10 (dez) diferenças entre os dois utilitários: o utilitário gcr-viewer escrito em gtk e o utilitário certViewer desenvolvido em Tk:



Certificados PKCS # 11 Token / Smartcard


Acima, falamos sobre o trabalho com certificados (navegue, obtenha a cadeia de certificados raiz, listas de certificados revogados, impressões digitais por sha1 e sha256 etc.) armazenadas em arquivos. Mas ainda existem certificados armazenados nos tokens / smartcards PKCS # 11. E o desejo natural não é apenas vê-los, exportar para um arquivo. Como fazer isso, descreveremos no seguinte artigo:

Source: https://habr.com/ru/post/pt440754/


All Articles