Utilidad multiplataforma en inglés para ver certificados rusos calificados x509

imagen Hoy, el uso de certificados digitales X509 v.3 se ha convertido en algo común. Cada vez más personas los utilizan para acceder al sitio web del Servicio Estatal, el Servicio de Impuestos Federales, licitaciones electrónicas, etc. Y cada vez más personas quieren saber qué hay en este "cofre" llamado certificado. Y si el certificado es un análogo de un pasaporte, entonces, ¿cómo se puede leer / ver? Sí, en los sistemas operativos hay varias utilidades para ver. Pero darán poco al ciudadano común. Tomemos, por ejemplo, la utilidad gcr-viewer, que, de hecho, es la herramienta estándar para ver en sistemas Linux y, por lo tanto, en sistemas operativos domésticos :



Visor estándar


La utilidad está bien hecha, conveniente. En general, está destinado a ser una utilidad universal para ver archivos que contienen datos en varios formatos criptográficos (certificados, solicitudes, firmas electrónicas / PKCS # 7, contenedores protegidos PKCS # 12, etc.). Pero, desafortunadamente, está diseñado para la criptografía occidental y no tiene en cuenta los oidos que se ingresan en su país. Y si mira la captura de pantalla, cuando se muestra la información sobre el titular del certificado, aparecen caracteres incomprensibles. A la izquierda están los propios oidos, y a la derecha en la 16ª forma, la estructura asn1 con sus valores. En este caso, estos son OGRN (1.2.643.100.1), SNILS (1.2.643.100.3) y TIN (1.2.643.3.131.1.1). Y así es como un ciudadano común debe asegurarse de que estos sean sus datos. No piense que esto es solo en Linux, es una característica común de cualquier visor de certificados. Y si miras más allá, entonces todo se vuelve incomprensible:



Aparecen algunas extensiones, identificadores y valores. En este caso, el oid 1.2.643.100.111 oculta el nombre del CIPF, que fue utilizado por el usuario para generar el par de claves, la clave privada a partir de la cual se usó para firmar la solicitud de certificado y la clave pública de la cual se encuentra en el certificado:



Y aquí, poco se entiende por el titular del certificado. Ni siquiera entiende qué algoritmo se utilizó para generar la clave, ya sea GOST R 34.10-2001 o GOST R 34.10-2012 y con qué longitud de clave.

Puedes seguir dando ejemplos. Por ejemplo, si la validez del certificado es clara, ¿dónde está la clave?

Hay dos preguntas más a las que los titulares de los certificados les gustaría tener una respuesta: ¿dónde puedo obtener la cadena de certificados raíz (o incluso mejor?) Y una pregunta similar en la lista de certificados revocados.

Y, por último, me gustaría tener una utilidad universal que tenga en cuenta las características de la PKI / PKI rusa, que es verdaderamente multiplataforma y se ejecuta en sistemas operativos nacionales y no domésticos . ¿Qué desarrollar? Por supuesto, en un lenguaje de script, aunque solo sea por su naturaleza multiplataforma.

Entonces recordé que el hermoso lenguaje de script Tcl (Tool Command Language) había celebrado recientemente su 30 aniversario . Es un placer programarlo. Tiene una gran cantidad de extensiones (paquete) que permiten casi todo. Entonces, para trabajar con estructuras ASN hay un paquete asn. Además, para trabajar con certificados (estamos interesados ​​en analizarlos en este caso) hay un paquete pki. Y para desarrollar una interfaz gráfica, hay un paquete Tk.

Lo mismo se puede decir sobre Pyton con Tkinter, y sobre Perl y sobre Ruby. Todos pueden elegir según su gusto. Nos detenemos en un montón de Tcl / Tk.

Tomaremos prestado el diseño gráfico para la utilidad de la utilidad gcr-viewer. Y un requisito más.

Como Habr tenía una versión en inglés , quería que la utilidad tuviera diferentes interfaces (ruso / inglés). Pero esta no es la razón principal. Más importante aún, cada vez más ciudadanos del mundo occidental se están convirtiendo en ciudadanos de la Federación Rusa, por ejemplo, el famoso actor Depardieu. Pueden objetar: él es francés. Pero también soy traductor militar del francés:



Por lo tanto, es fácil agregar una interfaz en francés. Pero creo que Depardieu no tiene problemas con el idioma inglés. Por otro lado, nuestro país es multinacional y sería bastante bueno si el software doméstico y el sistema operativo doméstico tuvieran al menos varias interfaces nacionales.
Corriendo un poco por delante, esto es lo que surgió:



Invitamos a un traductor


Entonces, comencemos con el "traductor". En la captura de pantalla, se esconde bajo la bandera nacional. El requisito principal para un traductor es la sincronización de la traducción, es decir. La capacidad de cambiar a otro idioma en cualquier momento. Las funciones del traductor en Tcl / Tk son realizadas por el paquete msgcat:

package require msgcat 

Para configurar el idioma actual, use el siguiente comando:

 msgcat::mclocale ru 

El vocabulario del "traductor" se almacena en el archivo ru.msg de la siguiente manera:

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

El siguiente es el texto de la prueba.
guión con traductor:
 #!/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]: " } 


En este script, el procedimiento :: changelang actúa como el traductor, que se llama cuando se presiona el botón .but_lang con la bandera.

Si ejecuta este script, verá claramente cómo funciona el traductor:



Obtenga la clave pública


Ahora que hemos decidido un traductor, procedamos con el análisis del certificado. Para hacer esto, necesitamos el paquete pki:

 package require pki). 

El paquete pki está diseñado para funcionar con claves y certificados de algoritmo RSA. Si el certificado (proc :: pki :: x509 :: parse_cert) se creó con un tipo de clave diferente, no recibiremos información sobre esta clave:

 # 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 } } 

Sorprendentemente, el algoritmo de clave pública aún regresa (ret (pubkey_algo))
La situación es la misma al analizar la solicitud 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" } } 

Pero aquí incluso devuelve información sobre el error. Pero hoy, además de RSA, por ejemplo, se utilizan claves en curvas elípticas de la UE, incluido GOST R 34.10-2012 (GOST R 34.10-2001 también por ahora).

Pero, por defecto, es suficiente devolver la estructura ASN de la clave pública que se encuentra en el certificado o solicitud, y el propio usuario analizará la clave pública según el tipo de clave. Para hacer esto, simplemente agregue la estructura ASN de clave pública en valores hexadecimales a los valores devueltos:

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

Todo, nada más que hacer. De esta manera, el procedimiento :: pki :: x509 :: parse_cert devuelve la mayoría de las extensiones de certificado por la simple razón de que no sabe cómo analizarlas (por ejemplo, subjectSignTool con nuestros certificados calificados), es decir da a discreción del usuario.

Por otro lado, el procedimiento :: pki :: x509 :: parse_cert devuelve uno de los resultados de un certificado tbs que contiene toda la información del certificado, excepto su firma (firma) y tipo de firma (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) 

Escribimos el procedimiento para extraer información de clave pública de un 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) } 

Y dado que estamos interesados ​​en la criptografía rusa, escribiremos inmediatamente el procedimiento para analizar la clave 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] } 

Sí, casi me lo pierdo: después de descargar el paquete pki, debe agregar a la matriz :: pki :: oids oids que caracterizan el certificado GOST y calificado o simplemente no están en esta 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" . . . 

También puede reponer el vocabulario del traductor agregando al archivo 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" . . . 
:


Cadena de certificados raíz y lista de revocación de certificados


Ya se ha discutido anteriormente cómo obtener una cadena de certificados raíz. Por analogía, se redacta un procedimiento para obtener una lista de certificados COS / CRL revocados. Puede encontrar el código fuente de la utilidad y sus distribuciones para Linux, OS X (macOS) y MS Windows


En el código fuente, puede encontrar todos los procedimientos para analizar extensiones de certificado.
A los opositores de Tk (Tcl / Tk, Python / Tkinter, etc.), les propongo encontrar, como dicen, 10 (diez) diferencias entre las dos utilidades: la utilidad gcr-viewer escrita en gtk y la utilidad certViewer desarrollada en Tk:



Certificados de token / tarjeta inteligente PKCS # 11


Anteriormente hablamos sobre trabajar con certificados (navegar, obtener la cadena de certificados raíz, listas de certificados revocados, huellas digitales de sha1 y sha256, etc.) almacenados en archivos. Pero todavía hay certificados almacenados en tokens / tarjetas inteligentes PKCS # 11. Y el deseo natural no es solo verlos, luego exportarlos a un archivo. Cómo hacer esto, lo describiremos en el siguiente artículo:

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


All Articles