Cryptographic Tokens PKCS # 11. Graphic utility "with the function of signing and adding a time stamp." Part 1

    In the comments on the article “Using PKCS # 11 Cryptographic Token Mechanisms in Scripting Languages”, the kovserg reader wrote :
    “We look forward to an article with the function of signing a document and adding a time stamp.”
    Earlier, another participant of the pas habr wrote that it would be great for PKCS # 11 tokens, "which everyone can count" (meaning primarily cryptographic operations for generating keys, generating and checking electronic ones), get rid of all kinds of interlayers and have one utility that could, using the mechanisms of the token itself, form a certificate request and sign documents, verify the signature of documents, verify the signature and validity of certificates.

    Acquaintance with the utility


    As a result, we present the utility to the court of users

    guipkcs7_tclpkcs11:



    The driving force of this utility is the PKCS # 11 cryptographic token with support for Russian cryptography at least GOST R 34.10-2012. If you intend to use public services , etc., you still need to purchase a token that has passed certified tests in the certification system of the FSB of Russia. If this is your internal electronic document management, then this, of course, is at your discretion. PKCS # 11 tokens can be different: software, hardware, or even cloud . The utility is written in the scripting language Tcl / Tk. When you purchase a PKCS # 11 token, do not forget to get or ask where you can download the libraries for the purchased token for various platforms. Libraries are generally freely available. The utility uses the TclPKCS11 package to access cryptographic and other token features . The utility starts by choosing a library that supports your tokens. Note that library libraries can simultaneously work with several tokens (combobox “select a token / smartcard”):



    A question may arise, but what should I do if the token is not initialized or I need to change PIN codes, etc.? The answer is simple - use the p11conf token configuration utility .

    To update the list of tokens (they disabled the token, added a new one), just click
    on the icon located to the right of the combobox “Choose a token / smart card”.
    In the “ combo” Certificate there are labels of all certificates stored on the selected (current) token:



    If you click to the icon located to the right of the “Certificate” combobox, a window with the contents of the certificate will appear:



    If you click on the “Save / Save” button in the viewing window, the contents of the parsed certificate will be saved in text format in the file you specified.
    To view information about the current token, you can click the "6. Information on the token" button or move the cursor to the token label:



    In order to find out which cryptographic mechanisms the current token supports, just click on the button “5. List of mechanisms”:



    Create a certificate request

    We pass to the main functions of the utility. And the first such function is to create a certificate request (button "3. Certificate request"): The



    message "Token does not support keys ..." appears if the selected token does not support the generation of this type of key. In this case, you need to select a different type of key or a different token. In this example, you can use the RuToken ECP 2.0 token (see the second screenshot). Combobox "Certificate Holder" allows you to specify who will own the certificate: an individual, a legal entity or an individual entrepreneur. Depending on this, the fields to be filled out will be formed on the following pages.

    A significant field here is the “Name CIPF” field. It is an integral part of a qualified certificate and indicates how the cryptographic information protection system will generate the key pair. You can find out the name of the cryptographic information protection certificate in the product form or at the time of purchase of the token. Does the type field in the token information coincide with the name of the cryptographic information protection system, I find it difficult to say. So it’s better to see the form. We press the Next button and fill in the required fields:



    When filling in, the utility tries to control the correctness of filling in the fields (email, OGRN, etc.) by issuing appropriate warnings. After filling in the main fields, you will be asked to determine the format and storage location of the certificate request on your computer. You will also be required to enter the PIN code of your token:



    After clicking the “Next” button, you will be asked to look again at what you entered and confirm your decision by pressing the “Finish” key:



    And, if you click the “Finish” button, a key pair will be generated on your token, created and The request is signed:



    Can you verify that the keys are generated and stored on the token? Yes. We press the button “7. Token objects”, enter the PIN code to access the token, and look for the SKO_PRIVATE_KEY and CKO_PUBLIV_KEY objects whose labels match the “COMMON NANE” (CN) field that you filled in when creating the certificate request. In our example, it was the "Almighty Habr":



    Looked and immediately go to another page. The best evidence that a key pair has been successfully created is the presence of the signed request itself. In order to verify this, press the “View request / certificate” button, select the saved request, click the “View certificate request” button and look at the key pair information:



    After we verify that the request has been successfully created, securely hide the token with the private key or we put it closer to our hearts (people of the older generation know how to store party or Komsomol tickets), copy the request for a flash drive, take the necessary documents (passport, etc.) and go to the CA to obtain a certificate. Yes, if this is not a departmental CA, then you still have to pay money. Everything is like with a passport .

    We go for a certificate in CA
    In this case, for issuing a certificate to the venerable Habr, we will use the CA from the pages of all Habr too. The CA starts reviewing our application:



    After the application has entered the CA database, the authorized administrator considers it and either rejects or approves:



    After the application is approved, the applicant together with the authorized person from the CA determines the purpose of using the certificate:



    And after that, nothing prevents the issuance of the certificate :



    After the certificate is issued, the CA employee exports the issued certificate to the Hon. Habr’s flash drive:



    We put the token certificate


    And so the lucky holder of the certificate returns to his native land and first of all decides to put the certificate for the token next to the key pair. To do this, on the main window of the utility, click the button “4. View request / certificate”, select the file with the certificate and the operation “View certificate” and press the button to perform the operation ”:



    We can also check the validity of the certificate (but we have not had time to revoke it) or the correctness of his signature by selecting the appropriate operation:



    Certificate Signing Verification Utility Code
    #!/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  \[\]\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"
    }


    But we are now interested in the operation of importing the received certificate to our token. Select the operation “Import certificate for token” and click the button “Perform operation”. The utility will verify the electronic signature of the certificate. To do this, you will be required to enter the PIN code for the token. And if everything goes well, then the certificate will be imported to the token: The



    label (nickname) of the certificate can be seen in the list of certificates:



    This is our personal certificate, the certificate for which there is a key pair. And if you look at the list of objects on the token again, we will find three objects that have the label "Almighty Habr from UTs 12_512" and the same CKA_ID. These three objectsare the certificate itself (CKO_CERTIFICATE), public (CKO_PUBLIC_KEY) and private (CKO_PRIVATE_KEY) keys. The label for this triple of objects is set as follows:
    from .

    Below we show how to change the label.

    Now that we have put the certificate on the token, how to access it? In order to gain access to the functions of working with certificates located on the token, just move the cursor to the “Certificate” label and press the right mouse button:



    We sign the first document with electronic signature


    Let's wait for the next article. You have to wait a couple of days. What else will be considered there can be understood from the screenshot:



    Continued here .

    Also popular now: