Rutoken,OpenSSL和用于签名消息的本地CA

前一段时间,该项目的框架需要限制同时访问在客户的局域网中运行的Web应用程序的计算机的数量。

使用硬件USB令牌来识别计算机的决定是自己决定的。 选择取决于Rutoken EDS:它无需驱动程序即可工作,要在Web应用程序中工作,您只需要开发人员发布的浏览器插件即可。 由于令牌应该识别计算机,而不是用户,因此使用它应该是完全“透明的”:如果存在,则系统只是在不询问用户不必要的问题的情况下以静默方式工作。

决定:登录系统时,使用Rootoken插件使用存储在Rutoken中的证书的非限定签名对用户凭据进行签名,然后在服务器上进行检查。 使用插件成功登录后,检查同一令牌的物理存在,如果没有,则注销系统。 在上述项目的框架内,这就足够了。

需要创建自己的证书颁发机构(CA),以交换签名消息,或者更确切地说,是将签名消息从客户端发送到服务器。 客户端证书必须位于私钥容器中的USB令牌上,并且必须使用OpenSSL在服务器上执行签名验证

因此,任务是: 在CA的Linux服务器上进行安装和配置。 部署用于识别USB令牌上的计算机的客户端证书

要解决它,您将需要:


  1. 我们创建CA所在的目录,并复制系统随附的OpenSSL配置(最新版本的Ubuntu中有/etc/ssl/openssl.cnf
  2. 我们配置“我们的” openssl.cnf:

    a)在用于连接令牌引擎的文件指令的开头添加:

    openssl_conf = openssl_def [ openssl_def ] engines = engine_section [ engine_section ] rtengine = gost_section [ gost_section ] dynamic_path = /path/to/rutoken/openssl/connector/librtengine.so MODULE_PATH = /path/to/rutoken/pkcs11/librtpkcs11ecp.so RAND_TOKEN = pkcs11:manufacturer=Aktiv%20Co.;model=Rutoken%20ECP default_algorithms = CIPHERS, DIGEST, PKEY, RAND 

    b)取消注释行

     # req_extensions = v3_req # The extensions to add to a certificate request 

    c)在[v3_req]部分中,指定以下参数:

     subjectSignTool = ASN1:FORMAT:UTF8,UTF8String:   extendedKeyUsage=emailProtection keyUsage=digitalSignature,nonRepudiation,keyEncipherment,dataEncipherment 

    d)在[v3_ca]部分中,从basicConstraints参数中删除关键选项:

     basicConstraints = CA:true 

    为了什么 诚实的回答:我不知道。 但是,我试图弄清楚该主题时下载的所有根证书示例都没有危险的迹象。 我问的是“为什么?” 比较有经验的同事。


    e)(可选)设置在发布自签名证书和生成用于发布客户端证书的请求时将提供的默认值。 这些参数在[req_distinguished_name]部分中

    带有_default后缀的参数是默认值。 一个例子:

     countryName = Country Name (2 letter code) countryName_default = AU countryName_min = 2 countryName_max = 2 

    当系统要求您输入countryName参数时,它将在方括号中指示默认情况下将保留值AU。


    这样就完成了OpenSSL配置的配置。 它仍然向OpenSSL指示有必要使用它。 为此,请设置环境变量OPENSSL_CONF:

     export OPENSSL_CONF=/path/to/your/openssl.cnf 
  3. 我们创建一个目录结构,其中将存储有关我们的CA的信息。
    为此,请转到刚刚编辑了openssl.cnf的创建目录,然后执行以下步骤:

    a)在其中创建子目录:

    demoCA
    demoCA /私人
    demoCA /新证书

    注意: demoCA名称在openssl.cnf文件的[CA_default]部分中阐明。 您可以更改它(在步骤2中),然后使用它代替demoCA。

    b)在demoCA目录中,创建一个空的index.txt文件和一个串行文件,使用文本编辑器打开该文件并在其中写入01行,这是已颁发证书的计数器。 颁发每个下一个证书后,此文件中的值增加一。
  4. 我们可以选择使用rtAdmin实用程序格式化令牌,现在一切就绪,可以部署CA。

    动作算法大致很简单:

    a)我们使用GOST算法颁发认证中心的根证书:

    • 生成私钥以颁发自签名CA证书
    • 使用生成的密钥生成自签名的X509证书

    b)在每个USB令牌上

    • 生成密钥对(所谓的私钥容器)
    • 使用生成的令牌密钥生成证书签名请求
    • 为此请求签发证书
    • 将证书保存在私钥容器中的令牌上

    以下是针对单个令牌的此算法的实现:

    CA证书的私钥生成(我们使用GOST算法):

     openssl genpkey -algorithm gost2012_256 -pkeyopt paramset:A -outform PEM -out demoCA/private/cakey.pem 

    我们签发自签名的CA证书:

     <b>openssl req -new -x509 -key demoCA/private/cakey.pem -out demoCA/certs/cacert.pem -extensions v3_ca -days +3650 -outform PEM 

    请注意:我们在命令行上指出,有必要使用openssl_cnf配置中的v3_ca扩展名。 在那里就是我们的CA。 有效期为10年。 CA的常识。 但是还有更多可能。

    在颁发证书的过程中,系统将要求您输入我们的openssl.cnf文件的[req_distinguished_name]部分中的参数值

    现在我们开始令牌操作。 如果令牌是新令牌或具有默认值的格式,则其上的用户PIN为12345678。我从这样的假设出发。 否则,您必须指定正确的用户PIN,并通常尝试确保在以下示例中,令牌上已存在的对象的名称与输入的对象的名称不重叠。

    首先,我们将生成一个密钥对。 OpenSSL无法在Rutoken上执行此操作,因此我们将使用OpenSC软件包中的pkcs11-tool实用程序:

     pkcs11-tool --module /path/to/your/librtpkcs11ecp.so --login --pin 12345678 --keypairgen --key-type GOSTR3410:A --id 303030303031 --label 'client01' 

    重要说明:我们指定的ID为303030303031。此ID的每两位仅是字符“ 0”和“ 1”的ASCII码。 对于使用OpenSSL的操作,它将看起来像“ id = 000001”

    生成证书请求:

     openssl req -utf8 -new -keyform engine -key 'pkcs11:id=000001' -engine rtengine -out demoCA/newcerts/client01.csr 

    如果一切都正确完成,那么系统

    • 要求输入密码
    • 将请求证书名称参数(来自[req_distinguished_name]部分)
    • 将发出证书签名请求文件

    使用此请求,我们签署了一个客户证书( 在示例中,该证书的有效期为1825天。 重要的是,该时间段不得超过您的根证书的有效期 ):

     openssl ca -utf8 -days +1825 -keyfile demoCA/private/cakey.pem -cert demoCA/certs/cacert.pem -in demoCA/newcerts/client01.csr -outdir demoCA/newcerts -out demoCA/certs/client01.pem 

    系统将显示证书,询问有关对其进行签名的决定(回答“ y”),以及有关保存新证书的决定(再次回答“ y”)。

    我们将收到的证书保存为令牌:

     pkcs11-tool --module /path/to/your/librtpkcs11ecp.so --login --pin 12345678 --id=303030303031 -w demoCA/certs/client01.pem -y cert 

    仅此而已。

    测试创建的“奇迹”。 为此,我们签名并验证短语“ Hello,world!”的签名:

     echo Hello,world! | openssl cms -nodetach -sign -signer demoCA/certs/client01.pem -keyform engine -inkey "pkcs11:id=000001" -engine rtengine -binary -noattr -outform PEM | openssl cms -verify -CAfile demoCA/certs/cacert.pem -inform PEM 

    如果一切都正确完成,系统将要求输入PIN码,对消息签名,然后验证签名,如果成功,则将显示原始消息和验证结果(“成功”)

    备注 。 返回标题任务并使用插件签名,应注意,默认情况下,插件提供的签名结果不是PEM格式,而是DER格式,以base64编码。 因此,要验证签名,必须首先从base64解码,然后在检查时指定输入DER格式。

    祝你好运!

Source: https://habr.com/ru/post/zh-CN444646/


All Articles