
En los comentarios sobre el artículo "Uso de mecanismos de
tokens criptográficos PKCS # 11 en lenguajes de
script ", el lector de
kovserg escribió :
"Esperamos un artículo con la función de firmar un documento y agregar una marca de tiempo".
Anteriormente, otro participante del
pas Habr
escribió que sería genial para los tokens PKCS # 11, "que todos pueden contar" (lo que significa principalmente operaciones criptográficas para generar claves, generar y verificar electrónicas), deshacerse de todo tipo de intercalares y tener Una utilidad que podría, utilizando los mecanismos del token, formar una solicitud de certificado y firmar documentos, verificar la firma de documentos, verificar la firma y la validez de los certificados.
Conocimiento de la utilidad.
Como resultado, presentamos la utilidad a la corte de usuarios

La fuerza impulsora de esta utilidad es el
token criptográfico
PKCS # 11 con soporte para la criptografía rusa al menos GOST R 34.10-2012. Si tiene la intención de utilizar
servicios públicos , etc., aún necesita comprar un token que haya pasado las pruebas certificadas en el sistema de certificación del FSB de Rusia. Si esta es su gestión interna de documentos electrónicos, entonces, por supuesto, queda a su discreción. Los tokens PKCS # 11 pueden ser diferentes: software, hardware o incluso en la
nube . La utilidad está escrita en el lenguaje de script
Tcl / Tk . Cuando compre un token PKCS # 11, no olvide obtener o preguntar dónde puede descargar las bibliotecas del token comprado para varias plataformas. Las bibliotecas están generalmente disponibles gratuitamente. La utilidad utiliza el paquete
TclPKCS11 para acceder a características criptográficas y otras
características de token. La utilidad comienza eligiendo una biblioteca que admita sus tokens. Tenga en cuenta que las bibliotecas de la biblioteca pueden trabajar simultáneamente con varios tokens (cuadro combinado "seleccione token / tarjeta inteligente"):

La pregunta puede surgir, pero ¿qué debo hacer si el token no se inicializa o si necesito cambiar los códigos PIN, etc.? La respuesta es simple: use la utilidad de configuración de token
p11conf .
Para actualizar la lista de tokens (deshabilite el token, agregue uno nuevo) simplemente haga clic en
por icono

ubicado a la derecha del cuadro combinado "Elija un token / tarjeta inteligente"
El "Certificado" de combox contiene etiquetas de todos los certificados almacenados en el token (actual) seleccionado:

Si haces clic en el ícono

ubicado a la derecha del certificado del cuadro combinado, aparece una ventana con el contenido del certificado:

Si hace clic en el botón "Guardar / Guardar" en la ventana de visualización, el contenido del certificado analizado en formato de texto se guardará en el archivo que especificó.
Para ver información sobre el token actual, puede hacer clic en el botón "6. Información sobre el token" o mover el cursor a la etiqueta del token:

Para saber qué mecanismos criptográficos admite el token actual, simplemente haga clic en el botón "5. Lista de mecanismos":

Crear una solicitud de certificado
Pasamos a las funciones principales de la utilidad. Y la primera de estas funciones es crear una solicitud de certificado (botón "3. Solicitud de certificado"):

El mensaje "El token no admite claves ..." aparece si el token seleccionado no admite la generación de este tipo de clave. En este caso, debe seleccionar un tipo diferente de clave o un token diferente. En este ejemplo, puede usar el token RuToken ECP 2.0 (vea la segunda captura de pantalla). El "Titular del certificado" del cuadro combinado le permite especificar quién será el propietario del certificado: un individuo, una entidad legal o un empresario individual. Dependiendo de esto, los campos a completar se formarán en las siguientes páginas.
Un campo significativo aquí es el campo "Nombre CIPF". Es una parte integral de un certificado calificado e indica cómo el sistema de protección de información criptográfica generará el par de claves. Puede encontrar el nombre del certificado de protección de la información criptográfica en el formulario del producto o en el momento de la compra del token. Si el campo de tipo en la información del token coincide con el nombre del sistema de protección de información criptográfica, me resulta difícil decirlo. Por lo tanto, es mejor ver el formulario. Haga clic en Siguiente y complete los campos obligatorios:

Al completar, la utilidad intenta controlar la corrección de completar los campos (correo electrónico, PSRN, etc.) emitiendo advertencias apropiadas. Después de completar los campos principales, se le pedirá que determine el formato y la ubicación de almacenamiento de la solicitud de certificado en su computadora. También se le pedirá que ingrese el código PIN de su token:

Después de hacer clic en el botón "Siguiente", se le pedirá que vuelva a mirar lo que ingresó y confirme su decisión presionando la tecla "Finalizar":

Y, si hace clic en el botón Finalizar, se generará un par de claves en su token, se creará y firmará una solicitud:

¿Y puede asegurarse de que las claves se generan y almacenan en el token? Si Presionamos el botón "7. Objetos de token", ingresamos el código PIN para acceder al token y buscamos los objetos SKO_PRIVATE_KEY y CKO_PUBLIV_KEY cuyas etiquetas coinciden con el campo "NOMBRE COMÚN" (CN) que completó al crear la solicitud de certificado. En nuestro ejemplo, fue el "Todopoderoso Habr":

Miró e inmediatamente ir a otra página. La mejor evidencia de que un par de claves se ha creado con éxito es la presencia de la solicitud firmada. Para verificar esto, presione el botón "Ver solicitud / certificado", seleccione la solicitud guardada, haga clic en el botón "Ver solicitud de certificado" y mire la información sobre el par de claves:

Después de asegurarse de que la solicitud se haya creado correctamente, oculte de forma segura el token con la clave privada o póngalo más cerca del corazón (las personas de la generación anterior saben cómo almacenar boletos para fiestas o Komsomol), copie la solicitud en la unidad flash, tome los documentos necesarios (pasaporte, etc.) e ir a la CA para obtener un certificado. Sí, si esto no es una CA departamental, entonces aún tiene que pagar dinero. Todo es como un
pasaporte .
Vamos por un certificado en CAEn este caso, para emitir un certificado al venerable Habr, también utilizaremos la
CA de las páginas de todo Habr. CA comienza a considerar nuestra aplicación:

Una vez que la aplicación ha ingresado a la base de datos de CA, el administrador autorizado la considera y rechaza o aprueba:

Después de que se aprueba la solicitud, el solicitante, junto con la persona autorizada de la CA, determina los propósitos de usar el certificado:

Y después de eso, nada impide la emisión del certificado:

Después de emitir el certificado, el empleado de CA exporta el certificado emitido a la unidad flash del Hon. Habr:

Ponemos el certificado del token
Y así, el afortunado titular del certificado regresa a su tierra natal y, en primer lugar, decide colocar el certificado para el token junto al par de claves. Para hacer esto, en la ventana principal de la utilidad, haga clic en el botón "4. Ver solicitud / certificado", seleccione el archivo con el certificado y la operación "Ver certificado" y haga clic en el botón para realizar la operación ":

También podemos verificar la validez del certificado (pero aún no hemos tenido tiempo de revocarlo) o la exactitud de su firma seleccionando la operación adecuada:

Código de utilidad de verificación de firma de certificado#!/usr/bin/env tclsh package require pki load ./tclpkcs11.so Tclpkcs11 # PKCS#11 #set pkcs11_module "/usr/local/lib64/librtpkcs11ecp_2.0.so" set pkcs11_module "/usr/local/lib64/libls11sw2016.so" puts "Connect the Token and press Enter" gets stdin yes set handle [pki::pkcs11::loadmodule $pkcs11_module] set slots [pki::pkcs11::listslots $handle] set i 0 foreach slotinfo $slots { set slotid [lindex $slotinfo 0] set slotlabel [lindex $slotinfo 1] set slotflags [lindex $slotinfo 2] if {[lsearch -exact $slotflags TOKEN_PRESENT] != -1} { set token_slotlabel $slotlabel set token_slotid $slotid # incr i break } } if {$i == 0} { puts " . ." exit } # PEM DER proc ::cert_to_der {data} { if {[string first "-----BEGIN CERTIFICATE-----" $data] != -1} { set data [string map {"\r\n" "\n"} $data] } array set parsed_cert [::pki::_parse_pem $data "-----BEGIN CERTIFICATE-----" "-----END CERTIFICATE-----"] if {[string range $parsed_cert(data) 0 0 ] == "0" } { # DER- "0" == 0x30 set asnblock $parsed_cert(data) } else { set asnblock "" } return $asnblock } proc usage {use error} { puts "Copyright(C) Orlov Vladimir (http://museum.lissi-crypto.ru/) 2019" if {$use == 1} { puts $error puts "Usage:\nverify_cert_with_pkcs11 <file with certificate> \[<file with CA certificate>\]\n" } } set countcert [llength $argv] if { $countcert < 1 || $countcert > 2 } { usage 1 "Bad usage!" exit } set file [lindex $argv 0] if {![file exists $file]} { usage 1 "File $file not exist" exit } # cert_user puts "Loading user certificate: $file" set fd [open $file] chan configure $fd -translation binary set cert_user [read $fd] close $fd if {$cert_user == "" } { usage 1 "Bad file with certificate user: $file" exit } set cert_user [cert_to_der $cert_user] if {$cert_user == ""} { puts "User certificate bad" exit } catch {array set cert_parse [::pki::x509::parse_cert $cert_user]} if {![info exists cert_parse]} { puts "User certificate bad" exit } #parray cert_parse if {$countcert == 1} { if {$cert_parse(issuer) != $cert_parse(subject)} { puts "Bad usage: not self signed certificate" } else { set cert_CA $cert_user } } else { set fileca [lindex $argv 1] if {![file exists $fileca]} { usage 1 "File $fileca not exist" exit } # cert_CA puts "Loading CA certificate: $fileca" set fd [open $fileca] chan configure $fd -translation binary set cert_CA [read $fd] close $fd if {$cert_CA == "" } { usage 1 "Bad file with certificate CA=$fileca" exit } set cert_CA [cert_to_der $cert_CA] if {$cert_CA == ""} { puts "CA certificate bad" exit } } foreach slotinfo $slots { set slotid [lindex $slotinfo 0] set slotlabel [lindex $slotinfo 1] set slotflags [lindex $slotinfo 2] if {[lsearch -exact $slotflags TOKEN_PRESENT] != -1} { set token_slotlabel $slotlabel set token_slotid $slotid } } # catch {array set cert_parse_CA [::pki::x509::parse_cert $cert_CA]} if {![info exists cert_parse_CA]} { puts "CA certificate bad" exit } # if {$cert_parse(issuer) != $cert_parse_CA(subject)} { puts "Bad issuer" exit } set aa [dict create pkcs11_handle $handle pkcs11_slotid $token_slotid] set tbs_cert [binary format H* $cert_parse(cert)] catch {set signature_algo_number [::pki::_oid_name_to_number $cert_parse(signature_algo)]} if {![info exists signature_algo_number]} { set signature_algo_number $cert_parse(signature_algo) } switch -- $signature_algo_number { "1.2.643.2.2.3" - "1 2 643 2 2 3" { # "GOST R 34.10-2001 with GOST R 34.11-94" set digest_algo "gostr3411" } "1.2.643.7.1.1.3.2" - "1 2 643 7 1 1 3 2" { # "GOST R 34.10-2012-256 with GOSTR 34.11-2012-256" set digest_algo "stribog256" } "1.2.643.7.1.1.3.3" - "1 2 643 7 1 1 3 3" { # "GOST R 34.10-2012-512 with GOSTR 34.11-2012-512" set digest_algo "stribog512" } default { puts " :$signature_algo_number" exit } } # tbs-!!!! set digest_hex [pki::pkcs11::digest $digest_algo $tbs_cert $aa] # asn- # binary scan $cert_CA H* cert_CA_hex array set infopk [pki::pkcs11::pubkeyinfo $cert_CA_hex [list pkcs11_handle $handle pkcs11_slotid $token_slotid]] set lpk [dict create pkcs11_handle $handle pkcs11_slotid $token_slotid] # pybkeyinfo lappend lpk "pubkeyinfo" lappend lpk $infopk(pubkeyinfo) array set lpkar $lpk puts "Enter PIN user for you token \"$token_slotlabel\":" gets stdin password if { [pki::pkcs11::login $handle $token_slotid $password] == 0 } { puts "Bad PIN" exit } if {[catch {set verify [pki::pkcs11::verify $digest_hex $cert_parse(signature) $lpk]} res] } { puts " =$res" exit } if {$verify != 1} { puts "BAD SIGNATURE=$verify" } else { puts "SIGNATURE OK=$verify" }
Pero ahora estamos interesados en la operación de importar el certificado recibido a nuestro token. Seleccione la operación "Importar certificado para token" y haga clic en el botón "Realizar operación". La utilidad verificará la firma electrónica del certificado. Para hacer esto, se le pedirá que ingrese el código PIN para el token. Y si todo va bien, el certificado se importará al token:

La etiqueta (apodo) del certificado se puede ver en la lista de certificados:

Este es nuestro certificado personal, un certificado para el cual hay un par de claves. Y si vuelve a mirar la lista de objetos en el token, encontraremos tres objetos que tienen la etiqueta "Almighty Habr de UTs 12_512" y el mismo CKA_ID. Estos
tres objetos son las claves del certificado en sí (CKO_CERTIFICATE), públicas (CKO_PUBLIC_KEY) y privadas (CKO_PRIVATE_KEY). La etiqueta para este triple de objetos se establece de la siguiente manera:
<Titular del certificado CN> del <editor del certificado CN>.
A continuación mostramos cómo cambiar la etiqueta.
Ahora que hemos puesto el certificado en el token, ¿cómo acceder a él? Para obtener acceso a las funciones de trabajar con certificados ubicados en el token, simplemente mueva el cursor a la etiqueta "Certificado" y presione el botón derecho del mouse:

Firmamos el primer documento con firma electrónica.
Esperemos al próximo artículo. Tienes que esperar un par de días. Lo que se considerará allí se puede entender de la captura de pantalla:
Continuado aquí .