⬆️ ⬇️

Using the eToken-EPGU plug-in to generate EDS

This is a continuation of the topic raised in a previous post about the Unified Portal of State Services (EPGU) and eToken-GOST EDS hardware keys.

First, the traditional description of the rake.



Quest number 1



After I received the token, I wanted to pull out the key certificate from it in order to return to interested persons in case something happens to check my EDS.

The rake is the first - neither SDK 4.55 nor SDK 5.1 did not want to recognize eToken GOST initialized and with the presence of a key.

A rake the second - CryptoPro 3.6 - too. What is strange - in the form of the certificate indicated that the key is generated CryptoPro CSP 3.6.

In search of truth, at least something that could help to access the contents of the token, I came across the Aladdinovsky JC-Web plugin.

The plugin identified the token, issued the SN, a list of certificates with the number 1 with ID = 3 and the name “Certificate”. But not more. An attempt to feed a PIN, or transfer data for a signature caused an exception.

The last hope remained - unzip the plugin used by the PSU for authorization purposes. Essentially the same JC-Web, only much simpler.

And I went to the website of state services.





Quest number 2



Quest number two was much easier.

Unscrambling the main page of the public services portal, I found out that the plugin has 2 fundamental JS methods: etgSignData, and etgGetCertificate. There are properties etgErrorCode, valid and version, but I will not consider them, due to the triviality of the latter.

These methods in the implementation of EPGU are wrapped in functions that simplify access to the plugin in the context of a web page.

I honestly copied them, only slightly corrected.

The result was such a simple web page that allows a) to pull out the certificate of the token holder (issued in Base64) and sign the data. The signature is also formed in the form of PKCS # 7, wrapped in Base64 encoding.

Sample page code for working with eToken GOST via EPGU plugin
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <meta http-equiv="Content-Type" content="text/html; charset=windows-1251"> <!--      --> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>  eToken    </title> </head> <body style="font-size: 11px; font-family: Verdana;"> <!--    --> <object id="etoken" type="application/x-csuser" width="0" height="0" style="overflow: hidden; float: left;"> <!--<param name="onload" value="pluginLoaded" />--> </object> <script type="text/javascript" language="javascript"> /** * Operations with eToken GOST using CSuser plugin * **/ //    .   -  ,  - -  //   1   (PKCS#7,   Base64),   5 -   window.SignDataByEToken = function(mess, pin) { var plugin = eTokenPlugin(); if (plugin.valid) { //  var return_array = new Object(); return_array[1] = ""; //cms(base64) return_array[5] = ""; //errorCode if (mess == "") { alert("   "); return return_array; } try { //  CMS return_array[1] = eTokenPlugin().etgSignData(1, 1, pin, mess, 0); if (eTokenPlugin().etgErrorCode == 28) return_array[1] = eTokenPlugin().etgSignData(1, 99, pin, mess, 0); } catch (e) { alert("  \r\n" + e.description); return return_array; } try { //    return_array[5] = eTokenPlugin().etgErrorCode; } catch (e) { alert(e.description); return return_array; } return return_array; } } //     .   - - .    Base64 window.GetCertificateByEToken = function(pin) { var cert = null; try { if (eTokenPlugin().valid) { cert = eTokenPlugin().etgGetCertificate(1, 1, pin); if (eTokenPlugin().etgErrorCode == 28) { cert = eTokenPlugin().etgGetCertificate(1, 99, pin); } } } catch (e) { alert(e.description); } return cert; } //     window.eTokenPlugin = function() { return document.getElementById("etoken"); }; //   .      window.checkPluginVersion = function(version) { if (!(eTokenPlugin() && eTokenPlugin().valid)) return false; var plugin_version = eTokenPlugin().version.split('.'); var portal_version = version.split('.'); if (isNaN(parseInt(plugin_version[0]))) return false; if (isNaN(parseInt(plugin_version[1]))) return false; if (isNaN(parseInt(plugin_version[2]))) return false; if (isNaN(parseInt(portal_version[0]))) return false; if (isNaN(parseInt(portal_version[1]))) return false; if (isNaN(parseInt(portal_version[2]))) return false; if (parseInt(plugin_version[0]) > parseInt(portal_version[0])) return true; if (parseInt(plugin_version[0]) < parseInt(portal_version[0])) return false; if (parseInt(plugin_version[1]) > parseInt(portal_version[1])) return true; if (parseInt(plugin_version[1]) < parseInt(portal_version[1])) return false; if (parseInt(plugin_version[2]) == 11 && parseInt(portal_version[2]) == 9) return false; //9>11 O_o if (parseInt(plugin_version[2]) > parseInt(portal_version[2])) return true; if (parseInt(plugin_version[2]) < parseInt(portal_version[2])) return false; return true; } // ,    function doLogin() { var PIN = document.getElementById("pin").value; var rd = document.getElementById("cleartext").value; var cert = GetCertificateByEToken(PIN); var ds = SignDataByEToken(rd, PIN); var dstext = ""; document.getElementById("cert").value = cert; for (name in ds) { dstext = dstext + name + " : " + ds[name] + "\r\n"; } document.getElementById("dsig").value = dstext; } </script> <!-- UI --> <div> <a id="btnLogin" onclick="doLogin();" style="border : solid 1px black; width : 140px; height : 40 px;" href="#"></a><br/><br/> <b>PIN-</b><br/> <input type="password" id="pin" style="width : 250px; border : solid 1px black;"/><br/><br/> <b></b><br/> <input type="text" id="cleartext" style="width : 250px; border : solid 1px black;"/><br/><br/> <b></b><br/> <input type="text" id="cert" style="width : 250px; border : solid 1px black;"/><br/><br/> <b></b><br/> <textarea id="dsig" style="width : 600px; height : 300px; border : solid 1px black;"></textarea><br/><br/> </div> </body> </html> 






')

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



All Articles