oo::class create token { variable libp11 variable handle variable infotok variable pintok variable nodet#Конструктор constructor {handlelp11 labtoken slottoken} { global pass global yespas set handle $handlelp11 set slots [pki::pkcs11::listslots $handle] array set infotok [] foreach slotinfo $slots { set slotflags [lindex $slotinfo 2] if {[lsearch -exact $slotflags TOKEN_PRESENT] != -1} { if {[string first $labtoken [lindex $slotinfo 1]] != -1} { set infotok(slotlabel) [lindex $slotinfo 1] set infotok(slotid) [lindex $slotinfo 0] set infotok(slotflags) [lindex $slotinfo 2] set infotok(token) [lindex $slotinfo 3] #Берется наш токен break } } } #Список найденных токенов в слотах if {[llength [array names infotok]] == 0 } { error "Constructor: Token not present for library : $handle" } #Объект какого токена set nodet [dict create pkcs11_handle $handle] dict set nodet pkcs11_slotid $infotok(slotid) set tit "Введите PIN-код для токене $infotok(slotlabel)" set xa [my read_password $tit] if {$xa == "no"} { error "Вы передумали вводить PIN для токена $infotok(slotlabel)" } set pintok $pass set pass "" set rr [my login ] if { $rr == 0 } { unset pintok error "Проверьте PIN-код токена $infotok(slotlabel)." } elseif {$rr == -1} { unset pintok error "Отсутствует токен." } my logout }#Методы класса method infoslot {} { return [array get infotok] } method listcerts {} { array set lcerts [] set certsder [pki::pkcs11::listcertsder $handle $infotok(slotid)] #Перебираем сертификаты foreach lc $certsder { array set derc $lc set lcerts($derc(pkcs11_label)) [list $derc(cert_der) $derc(pkcs11_id)] #parray derc } return [array get lcerts] } method read_password {tit} { global yespas global pass set tit_orig "$::labpas" if {$tit != ""} { set ::labpas "$tit" } tk busy hold ".st.fr1" tk busy hold ".st.fr3" #place .topPinPw -in .st.fr1.fr2_certs.labCert -relx 1.0 -rely 3.0 -relwidth 3.5 place .topPinPw -in .st.labMain -relx 0.35 -rely 5.0 -relwidth 0.30 set yespas "" focus .topPinPw.labFrPw.entryPw vwait yespas catch {tk busy forget ".st.fr1"} catch {tk busy forget ".st.fr3"} if {$tit != ""} { set ::labpas "$tit_orig" } place forget .topPinPw return $yespas } unexport read_password method rename {type ckaid newlab} { if {$type != "cert" && $type != "key" && $type != "all"} { error "Bad type for rename " } set uu $nodet lappend uu "pkcs11_id" lappend uu $ckaid lappend uu "pkcs11_label" lappend uu $newlab if { [my login ] == 0 } { unset uu return 0 } pki::pkcs11::rename $type $uu my logout return 1 } method changeid {type ckaid newid} { if {$type != "cert" && $type != "key" && $type != "all"} { error "Bad type for changeid " } set uu $nodet lappend uu "pkcs11_id" lappend uu $ckaid lappend uu "pkcs11_id_new" lappend uu $newid if { [my login ] == 0 } { unset uu return 0 } pki::pkcs11::rename $type $uu my logout return 1 } method delete {type ckaid} { if {$type != "cert" && $type != "key" && $type != "all" && $type != "obj"} { error "Bad type for delete" } set uu $nodet lappend uu "pkcs11_id" lappend uu $ckaid my login ::pki::pkcs11::delete $type $uu my logout return 1 } method deleteobj {hobj} { set uu $nodet lappend uu "hobj" lappend uu $hobj#tk_messageBox -title "class deleteobj" -icon info -message "hobj: $hobj\n" -detail "$uu" return [::pki::pkcs11::delete obj $uu ] } method listmechs {} { set llmech [pki::pkcs11::listmechs $handle $infotok(slotid)] return $llmech } method pubkeyinfo {cert_der_hex} { array set linfopk [pki::pkcs11::pubkeyinfo $cert_der_hex $nodet] return [array get linfopk] } method listobjects {type} { if {$type != "cert" && $type != "pubkey" && $type != "privkey" && $type != "all" && $type != "data"} { error "Bad type for listobjects " } set allobjs [::pki::pkcs11::listobjects $handle $infotok(slotid) $type] return $allobjs } method importcert {cert_der_hex cka_label} { set uu $nodet dict set uu pkcs11_label $cka_label if {[catch {set pkcs11id [pki::pkcs11::importcert $cert_der_hex $uu]} res] } { error "Cannot import this certificate:$res" # return 0 } return $pkcs11id } method login {} { set wh 1 set rl -1 while {$wh == 1} { if {[catch {set rl [pki::pkcs11::login $handle $infotok(slotid) $pintok]} res]} { if {[string first "SESSION_HANDLE_INVALID" $res] != -1} { pki::pkcs11::closesession $handle continue } elseif {[string first "TOKEN_NOT_PRESENT" $res] != -1} { set wh 0 continue } } break } if {$wh == 0} { return -1 } return $rl } method logout {} { return [pki::pkcs11::logout $handle $infotok(slotid)] } method keypair {typegost parkey} { my login set skey [pki::pkcs11::keypair $typegost $parkey $nodet] my logout return $skey } method digest {typehash source} { return [pki::pkcs11::digest $typehash $source $nodet] } method signkey {ckm digest hobj_priv} { set uu $nodet dict set uu hobj_privkey $hobj_priv my login set ss [pki::pkcs11::sign $ckm $digest $uu] my logout return $ss } method signcert {ckm digest pkcs11_id} { set uu $nodet dict set uu pkcs11_id $pkcs11_id my login set ss [pki::pkcs11::sign $ckm $digest $uu] my logout return $ss } method verify {digest signature asn1pubkey} { set uu $nodet dict set uu pubkeyinfo $asn1pubkey return [pki::pkcs11::verify $digest $signature $uu] } method tokenpresent {} { set slots [pki::pkcs11::listslots $handle] 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} { if {infotok(slotlabel) == $slotlabel && $slotid == $infotok(slotid)} { return 1 } } } return 0 } method setpin {type tpin newpin} { if {$type != "user" && $type != "so"} { return 0 } if {$type == "user"} { if {$tpin != $pintok} { return 0 } } set ret [::pki::pkcs11::setpin $handle $infotok(slotid) $type $tpin $newpin] if {$type == "user"} { if {$ret} { set pitok $newpin } } return $ret } method inituserpin {sopin upin} { set ret [::pki::pkcs11::inituserpin $handle $infotok(slotid) $sopin $upin] return $ret } method importkey {uukey} { set uu $nodet append uu " $uukey" my login if {[catch {set impkey [pki::pkcs11::importkey $uu ]} res] } { set impkey 0 } my logout return $impkey }#Деструктор destructor { variable handle if {[info exists pintok]} { my login } # ::pki::pkcs11::unloadmodule $handle }}
I. Конструктор класса Token
Итак, конструктор класса Token выглядит следующим образом:
import sysimport pyp11class Token: def __init__ (self, handlelp11, slottoken, serialnum): flags = '' self.pyver = sys.version[0] if (self.pyver == '2'): print ('Только для python3') quit()#Сохраняем handle библиотеки PKCS#11 self.handle = handlelp11#Сохраняем номер слота с токеном self.slotid = slottoken#Сохраняем серийный номер токена self.sn = serialnum#Проверяем наличие в указанном слоте токена с заданным серийным номером ret, stat = self.tokinfo()#Проверяем код возврата if (stat != ''):#Возвращаем информацию об ошибке self.returncode = stat return#Экземпляр класса (объект) успешно создан
Параметрами конструктора (метода __init__) являются (помимо обязательного self) handle библиотеки токена (handlelp11), номер слота (slottoken), в котором должен находиться токен, и серийный номер токена (serialnum).
Для получения handle библиотеки pkcs#11, номеров слотов и информации о находящихся в них токенах можно использовать следующий скрипт:
#!/usr/bin/python3import sysimport pyp11from Token import Tokendef listslots (handle): slots = pyp11.listslots(aa) i = 0 lslots = [] for v in slots: for f in v[2]: if (f == 'TOKEN_PRESENT'): i = 1 lslots.append(v) break i += 1 return (lslots)#Библиотеки для Linux#Программный токенlib = '/usr/local/lib64/libls11sw2016.so'#Облачный токен#lib = '/usr/local/lib64/libls11cloud.so'#Аппаратный токен#lib = '/usr/local/lib64/librtpkcs11ecp_2.0.so'#Библиотеки для Windows#lib='C:\Temp\ls11sw2016.dll'try:#Вызываем команду загрузки библиотеки и получаем её handle (дескриптор библиотеки) aa = pyp11.loadmodule(lib) print('Handle библиотеки ' + lib + ': ' + aa)except: print('Except load lib: ') e = sys.exc_info()[1] e1 = e.args[0]#Печать ошибки print (e1) quit()#Список слотовslots = listslots(aa)i = 0for v in slots: for f in v[2]: if (f == 'TOKEN_PRESENT'): if (i == 0): print ('\nИнформация о токенах в слотах\n') it = v[3] print ('slotid=' + str(v[0])) print ('\tFlags=' + str(v[2])) print ('\tLabel="' + it[0].strip() + '"') print ('\tManufacturer="' + it[1].strip() + '"') print ('\tModel="' + it[2].strip() + '"') print ('\tSerialNumber="' + it[3].strip() + '"') i = 1 break i += 1pyp11.unloadmodule(aa)if (i == 0): print ('Нет ни одного подключенного токена. Вставьте токен и повторите операцию')quit()
Если с библиотекой и слотом всё ясно, то с серийным номером токена может возникнуть вопрос а зачем этот параметр нужен и почему именно он, а, например, не метка токена. Сразу оговоримся, что это принципиально для извлекаемых токенов, когда злоумышленником (или случайно) один токен в слоте будет заменён другим токеном. Более того, различные экземпляры токена могут иметь одинаковые метки. И наконец, токен может быть еще не проинициализирован или владелец будет его переинициализировать, в частности, сменит метку токена. Теоретически даже серийный номер не гарантирует его идентичность, оптимально учитывать всю информацию о токене (серийный номер, модель, производитель). В задачи конструктора и входит сохранение в переменных создаваемого экземпляра класса аргументов объекта токен:
...#Сохраняем handle библиотеки PKCS#11 self.handle = handlelp11#Сохраняем номер слота с токеном self.slotid = slottoken#Сохраняем серийный номер токена self.sn = serialnum...
Проверкой наличия указанного токена в указанном слоте занимается метод tokinfo(), определенный в данном классе.
Метод tokinfo возвращает два значения (см. выше в конструкторе):
#Проверяем наличие в указанном слоте токена с заданным серийным номером ret, stat = self.tokinfo()
В первой переменной (ret) содержится результат выполнения метода, а во второй (stat) информация о том, как завершилось выполнение метода. Если вторая переменная пуста, то метод tokinfo успешно выполнился. Если вторая переменная не пуста, то выполнение метода завершилось с ошибкой. Информация об ошибке будет находиться в этой переменной. При обнаружении ошибки выполнения метода self.tokinfo конструктор записывает её в переменную returncode:
#Проверяем наличие в указанном слоте токена с заданным серийным номером ret, stat = self.tokinfo()#Проверяем код возврата if (stat != ''):#Возвращаем информацию об ошибке в переменной returncode self.returncode = stat return
После создания объекта (экземпляра класса) необходимо проверить значение переменной returncode, чтобы быть уверенным в том, что объект для указанного токена создан:
#!/usr/bin/python3import sysimport pyp11from Token import Token#Выбираем библиотеку#Аппаратный токенlib = '/usr/local/lib64/librtpkcs11ecp_2.0.so'try: aa = pyp11.loadmodule(lib)except: e = sys.exc_info()[1] e1 = e.args[0] print (e1) quit()#Серийный номер токенаsn = '9999999999999999'slot = 110#Создаем объект токенаt1 = Token(aa, slot, sn)#Проверка переменной returncodeif (t1.returncode != ''):#Объект создан с ошибкой print (t1.returncode)#Уничтожение объекта del t1#Завершение скрипта quit()#объект успешно создан. . .
Если обнаружена ошибка при создании объекта, то целесообразно этот объект уничтожить:
del <идентификатор объекта>
II. Архитектура методов в классе Token
Главным принципом при написании методов было то, чтобы обработка исключений была внутри методов, а информация об исключениях (ошибках) возвращалась в текстовом виде. Исходя из этого все методы возвращают два значения: собственно результат выполнения и информацию об ошибке. Если ошибок нет, то второе значение пустое. Мы это уже видели на примере использования метода tokinfo в конструкторе. А вот и сам код метода tokinfo:
def tokinfo(self): status = ''#Получаем список слотов try: slots = pyp11.listslots(self.handle) except:#Проблемы с библиотекой токена e = sys.exc_info()[1] e1 = e.args[0] dd = '' status = e1 return (dd, status) status = ''#Ищем заданный слот с указанным токеном#Перебираем слоты for v in slots:#Ищем заданный слот if (v[0] != self.slotid): status = "Ошибочный слот" continue self.returncode = ''#Список флагов текущего слота self.flags = v[2]#Проверяем наличие в стоке токена if (self.flags.count('TOKEN_PRESENT') !=0):#Проверяем серийный номер токена tokinf = v[3] sn = tokinf[3].strip() if (self.sn != sn): status = 'Серийный номер токена=\"' + sn + '\" не совпадает с заданным \"' + self.sn + '\"' dd = '' return (dd, status) status = '' break else: dd = '' status = "В слоте нет токена" return (dd, status) tt = tokinf dd = dict(Label=tt[0].strip()) dd.update(Manufacturer=tt[1].strip()) dd.update(Model=tt[2].strip()) dd.update(SerialNumber=tt[3].strip()) self.infotok = dd#Возвращаемые значения return (dd, status)
import sysimport pyp11class Token: def __init__ (self, handlelp11, slottoken, serialnum): flags = '' self.pyver = sys.version[0] if (self.pyver == '2'): print ('Только для python3') quit()#Сохраняем handle библиотеки PKCS#11 self.handle = handlelp11#Сохраняем номер слота с токеном self.slotid = slottoken#Сохраняем серийный номер токена self.sn = serialnum#Проверяем наличие в указанном слоте с токена с заданным серийным номером ret, stat = self.tokinfo()#Проверяем код возврата if (stat != ''):#Возвращаем информацию об ошибке self.returncode = stat return#Экземпляр класса (объект) успешно создан def tokinfo(self): status = ''#Получаем список слотов try: slots = pyp11.listslots(self.handle) except:#Проблемы с библиотекой токена e = sys.exc_info()[1] e1 = e.args[0] dd = '' status = e1 return (dd, status) status = ''#Ищем заданный слот с указанным токеном#Перебираем слоты for v in slots:#Ищем заданный слот if (v[0] != self.slotid): status = "Ошибочный слот" continue self.returncode = ''#Список флагов текущего слота self.flags = v[2]#Проверяем наличие в стоке токена if (self.flags.count('TOKEN_PRESENT') !=0):#Проверяем серийный номер токена tokinf = v[3] sn = tokinf[3].strip() if (self.sn != sn): status = 'Серийный номер токена=\"' + sn + '\" не совпадает с заданным \"' + self.sn + '\"' dd = '' return (dd, status) status = '' break else: dd = '' status = "В слоте нет токена" return (dd, status) tt = tokinf dd = dict(Label=tt[0].strip()) dd.update(Manufacturer=tt[1].strip()) dd.update(Model=tt[2].strip()) dd.update(SerialNumber=tt[3].strip()) self.infotok = dd return (dd, status) def listcerts(self): try: status = '' lcerts = pyp11.listcerts(self.handle, self.slotid) except:#Проблемы с библиотекой токена e = sys.exc_info()[1] e1 = e.args[0] lcerts = '' status = e1 return (lcerts, status) def listobjects(self, type1, value = '' ): try: status = '' if (value == ''): lobjs = pyp11.listobjects(self.handle, self.slotid, type1) else: lobjs = pyp11.listobjects(self.handle, self.slotid, type1, value) except:#Проблемы с библиотекой токена e = sys.exc_info()[1] e1 = e.args[0] lobjs = '' status = e1 return (lobjs, status) def rename(self, type, pkcs11id, label): try: status = '' dd = dict(pkcs11_id=pkcs11id, pkcs11_label=label) ret = pyp11.rename(self.handle, self.slotid, type, dd) except:#Проблемы с библиотекой токена e = sys.exc_info()[1] e1 = e.args[0] ret = '' status = e1 return (ret, status) def changeckaid(self, type, pkcs11id, pkcs11idnew): try: status = '' dd = dict(pkcs11_id=pkcs11id, pkcs11_id_new=pkcs11idnew) ret = pyp11.rename(self.handle, self.slotid, type, dd) except:#Проблемы с библиотекой токена e = sys.exc_info()[1] e1 = e.args[0] ret = '' status = e1 return (ret, status) def login(self, userpin): try: status = '' bb = pyp11.login (self.handle, self.slotid, userpin) except: e = sys.exc_info()[1] e1 = e.args[0] bb = 0 status = e1 return (bb, status) def logout(self): try: status = '' bb = pyp11.logout (self.handle, self.slotid) except: e = sys.exc_info()[1] e1 = e.args[0] bb = 0 status = e1 return (bb, status) def keypair(self, typek, paramk, labkey):#Параметры для ключей gost2012_512 = ['1.2.643.7.1.2.1.2.1', '1.2.643.7.1.2.1.2.2', '1.2.643.7.1.2.1.2.3'] gost2012_256 = ['1.2.643.2.2.35.1', '1.2.643.2.2.35.2', '1.2.643.2.2.35.3', '1.2.643.2.2.36.0', '1.2.643.2.2.36.1', '1.2.643.7.1.2.1.1.1', '1.2.643.7.1.2.1.1.2', '1.2.643.7.1.2.1.1.3', '1.2.643.7.1.2.1.1.4'] gost2001 = ['1.2.643.2.2.35.1', '1.2.643.2.2.35.2', '1.2.643.2.2.35.3', '1.2.643.2.2.36.0', '1.2.643.2.2.36.1']#Тип ключа typekey = ['g12_256', 'g12_512', 'gost2001'] genkey = '' if (typek == typekey[0]): gost = gost2012_256 elif (typek == typekey[1]): gost = gost2012_512 elif (typek == typekey[2]): gost = gost2001 else: status = 'Неподдерживаемый тип ключа' return (genkey, status) if (gost.count(paramk) == 0) : status = 'Неподдерживаемые параметры ключа' return (genkey, status) try:#Ошибок нет, есть ключевая пара status = '' genkey = pyp11.keypair(self.handle, self.slotid, typek, paramk, labkey) except:#Не удалось создать ключевую пару e = sys.exc_info()[1] e1 = e.args[0] print (e1)#Возвращаеи текст ошибки в словаре status = e1 return (genkey, status) def digest(self, typehash, source):#Считаем хэш try: status = '' digest_hex = pyp11.digest (self.handle, self.slotid, typehash, source) except: e = sys.exc_info()[1] e1 = e.args[0]#Возвращаеи текст ошибки в словаре status = e1 digest_hex = '' return (digest_hex, status)#Формирование подписи def sign(self, ckmpair, digest_hex, idorhandle):#Для подписи можно использовать CKA_ID или handle закрытого ключа try: status = '' sign_hex = pyp11.sign(self.handle, self.slotid, ckmpair, digest_hex, idorhandle) except: e = sys.exc_info()[1] e1 = e.args[0]#Возвращаеи текст ошибки в словаре status = e1 sign_hex = '' return (sign_hex, status)#Проверка подписи def verify(self, digest_hex, sign_hex, pubkeyinfo):#Для подписи можно использовать CKA_ID или handle закрытого ключа try: status = '' verify = pyp11.verify(self.handle, self.slotid, digest_hex, sign_hex, pubkeyinfo) except: e = sys.exc_info()[1] e1 = e.args[0]#Возвращаеи текст ошибки в status verify = 0 status = e1 return (verify, status)#Инициализировать токен def inittoken(self, sopin, labtoken): try: status = '' dd = pyp11.inittoken (self.handle, self.slotid, sopin, labtoken) except: e = sys.exc_info()[1] e1 = e.args[0]#Возвращаеи текст ошибки в status dd = 0 status = e1 return (dd, status)#Инициализировать пользовательский PIN-код def inituserpin(self, sopin, userpin): try: status = '' dd = pyp11.inituserpin (self.handle, self.slotid, sopin, userpin) except: e = sys.exc_info()[1] e1 = e.args[0]#Возвращаеи текст ошибки в status dd = 0 status = e1 return (dd, status)#Сменить пользовательский PIN-код def changeuserpin(self, oldpin, newpin): try: status = '' dd = pyp11.setpin (self.handle, self.slotid, 'user', oldpin, newpin) except: e = sys.exc_info()[1] e1 = e.args[0]#Возвращаеи текст ошибки в status dd = 0 status = e1 self.closesession () return (dd, status) def closesession(self): try: status = '' dd = pyp11.closesession (self.handle) except: e = sys.exc_info()[1] e1 = e.args[0]#Возвращаеи текст ошибки в status dd = 0 status = e1 return (dd, status) def parsecert(self, cert_der_hex): try: status = '' dd = pyp11.parsecert (self.handle, self.slotid, cert_der_hex) except:#Не удалось разобрать сертификат e = sys.exc_info()[1] e1 = e.args[0]#Возвращаеи текст ошибки в status dd = '' status = e1 return (dd, status) def importcert(self, cert_der_hex, labcert): try: status = '' dd = pyp11.importcert (self.handle, self.slotid, cert_der_hex, labcert) except: e = sys.exc_info()[1] e1 = e.args[0]#Возвращаеи текст ошибки в status dd = '' status = e1 return (dd, status) def delobject(self, hobject): try: status = '' hobjc = dict(hobj=hobject) dd = pyp11.delete(self.handle, self.slotid, 'obj', hobjc) except: e = sys.exc_info()[1] e1 = e.args[0]#Возвращаеи текст ошибки в status dd = '' status = e1 return (dd, status) def delete(self, type, pkcs11id): if (type == 'obj'): dd = '' status = 'delete for type obj use nethod delobject' return (dd, status) try: status = '' idobj = dict(pkcs11_id=pkcs11id) dd = pyp11.delete(self.handle, self.slotid, type, idobj) except: e = sys.exc_info()[1] e1 = e.args[0]#Возвращаеи текст ошибки в status dd = '' status = e1 return (dd, status) def listmechs(self): try: status = '' dd = pyp11.listmechs (self.handle, self.slotid) except:#Не удалось получить список механизмов токена e = sys.exc_info()[1] e1 = e.args[0]#Возвращаеи текст ошибки в status dd = '' status = e1 return (dd, status)
Рассмотрим импользование функционала модуля pyp11 и аналогичных операторов с использованием класса Token.
В последнем случае необходимо будет создать и объект токена:
<дескриптор объекта> = Token(<дескриптор библиоткети>, <номер слота>, <серийный номер>)if (<дескриптор объекта>.returncode != ''): print('Ошибка при создании объекта:')#Печать ошибки print(<дескриптор объекта>.returncode)#Уничтожение объекта del <дескриптор объекта> quit()
Начнем с инициализации токена:
try: ret = pyp11.inittoken (<дескриптор библиоткети>, <номер слота>, <SO-PIN>, <метка токена>)except:#Не удалось проинициализировать токен e = sys.exc_info()[1] e1 = e.args[0] print (e1) quit()
Аналогичный код при использовании класса Token выглядит так (идентификатор объекта t1):
ret, stat = t1.inittoken(<SO-PIN>, <метка токена>)#Проверка корретности инициализацииif (stat != ''): print('Ошибка при инициализации токена:')#Печать ошибки print(stat) quit()
Далее мы просто дадим соответствие основных операторов модуля pyp11 и методов класса Token без обработки исключений и ошибок:
<handle> := <дескриптор библиотеки pkcs11><slot> := <дескриптор слота с токеном><error> := <переменная с текстом ошибки><ret> := <результат выполнения оператора><cert_der_hex> := <сертификат в DER-формате в HEX-кодировке>=================================================#Инициализация пользовательского PIN-кода<ret> = pyp11.inituserpin (<handle>, <slot>, <SO-PIN>, <USER-PIN>)<ret>, <error> = <идентификатор объекта>.inituserpin (<SO-PIN>, <USER-PIN>)#Смена USER-PIN кода<ret> = pyp11.setpin (<handle>, <slot>, 'user', <USER-PIN старый>, <USER-PIN новый>)<ret>, <error> = t1.changeuserpin (<USER-PIN старый>, <USER-PIN новый>)#Смена SO-PIN кода<ret> = pyp11.setpin (<handle>, <slot>, 'so', <SO-PIN старый>, <SO-PIN новый>)<ret>, <error> = t1.changesopin (<SO-PIN старый>, <SO-PIN новый>)#Login<ret> = pyp11.login (<handle>, <slot>, <USER-PIN>)<ret>, <error> = t1.login (<USER-PIN>)#Logout<ret> = pyp11.logout (<handle>, <slot>)<ret>, <error> = t1.logout ()#Закрытие сессии<ret> = pyp11.closesession (<handle>)<ret>, <error> = t1.closesession ()#Список сертификатов на токене<ret> = pyp11.listcerts (<handle>, <slot>)<ret>, <error> = t1.listcerts ()#Список объектов на токене<ret> = pyp11.listobjects (<handle>, <slot>, <'cert' | 'pubkey' | 'privkey' | 'data' | 'all'> [, 'value'])<ret>, <error> = t1.listobjects (<'cert' | 'pubkey' | 'privkey' | 'data' | 'all'> [, 'value'])#Разбор сертификата<ret> = pyp11.parsecert (<handle>, <slot>, <cert_der_hex>)<ret>, <error> = t1.parsecert(<cert_der_hex>)#Импорт сертификата<ret> = pyp11.importcert (<handle>, <slot>, <cert_der_hex>, <Метка сертификата>)<ret>, <error> = t1.importcert(<cert_der_hex>, <Метка сертификата>)#Вычисление хэша<ret> = pyp11.digest (<handle>, <slot>, <тип алгоритма>, <контент>)<ret>, <error> = t1.digest(<тип алгоритма>, <контент>)#Вычисление электронной подписи<ret> = pyp11.digest (<handle>, <slot>, <механизм подписи>, <хэш от контента>, <CKA_ID | handle закрытого ключа>)<ret>, <error> = t1.digest(<механизм подписи>, <хэш от контента>, <CKA_ID | handle закрытого ключа>)#Проверка электронной подписи<ret> = pyp11.verify (<handle>, <slot>, <хэш от контента>, <подпись>, <asn1-структура subjectpublickeyinfo в hex>)<ret>, <error> = t1.verify(<хэш от контента>, <подпись>, <asn1-структура subjectpublickeyinfo в hex>)#Генерация ключевой пары<ret> = pyp11.keypair (<handle>, <slot>, <тип ключа>, <OID криптопараметра>, <CKA_LABEL>)<ret>, <error> = t1.keypair(<тип ключа>, <OID криптопараметра>, <CKA_LABEL>)
III. Сборка и установка модуля pyp11 с классом Token
Сборка и установка модуля pyp11 с классом Token ничем не отличается от описанной в первой части.
Итак, скачиваем архив и распаковываем его. Заходим в папку PythonPKCS11 и выполняем команду установки:
python3 setup.py install
После установки модуля переходим в папку tests и запускаем тесты для модуля pyp11.
Для тестирования класса Token переходим в папку test/classtoken.
Для подключения модуля pyp11 и класса Token в скрипты достаточно добавить следующие операторы:
import pyp11from Token import Token
IV. Заключение
В ближайшее время должна появиться и третья часть статьи, в которой будет рассказано, как добавить поддержку российской криптографии в проект PyKCS11.
P.S. Хочу сказать спасибо svyatikov за то, что помог протестировать проект на платформе Windows.