Rutoken, OpenSSL e uma CA local para assinar mensagens

Há algum tempo, na estrutura do projeto, era necessário limitar o número simultâneo de computadores que têm acesso a um aplicativo da Web em execução na rede local do cliente.

A decisão de usar tokens USB de hardware para identificar o computador veio por si só. A opção ficou com o Rutoken EDS: ele funciona sem drivers. Para trabalhar em um aplicativo da Web, você só precisa de um plug-in de navegador lançado pelo desenvolvedor. Como o token deve identificar o computador, não o usuário, o trabalho com ele deve ser completamente "transparente": se existir, o sistema simplesmente trabalha silenciosamente, sem fazer perguntas desnecessárias ao usuário.

Foi decidido: ao fazer login no sistema, assine as credenciais do usuário com uma assinatura não qualificada de um certificado armazenado no Rutoken usando o plug-in Rootoken e verifique o servidor. Após um login bem-sucedido usando o plug-in, verifique a presença física do mesmo token e, na falta dele, efetue logout do sistema. Dentro da estrutura do projeto mencionado, isso foi suficiente.

É necessário criar sua própria Autoridade de Certificação (CA) para a troca de mensagens assinadas, ou melhor, para a transferência de mensagens assinadas do cliente para o servidor. Os certificados de cliente devem estar localizados em tokens USB em contêineres de chave privada e a verificação de assinatura deve ser realizada no servidor usando o OpenSSL

Portanto, a tarefa: instalação e configuração no servidor Linux da CA. Implante certificados de cliente que identificam computadores em tokens USB .

Para resolvê-lo, você precisará de:


  1. Criamos um diretório em que a CA estará localizada e copiamos a configuração do OpenSSL incluída no sistema (há /etc/ssl/openssl.cnf nas últimas versões do Ubuntu)
  2. Nós configuramos "our" openssl.cnf:

    a) Adicione ao início das diretivas de arquivo para conectar o mecanismo do token:

    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) descomente a linha

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

    c) na seção [v3_req] , especifique os seguintes parâmetros:

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

    d) na seção [v3_ca], remova a opção crítica do parâmetro basicConstraints:

     basicConstraints = CA:true 

    Para que? Resposta honesta: eu não sei. No entanto, todos os exemplos de certificados raiz que eu baixei enquanto tentava descobrir o tópico estavam sem um sinal crítico. Estou fazendo a pergunta "para quê?" colegas mais experientes.


    e) opcionalmente, defina os valores padrão que serão oferecidos ao emitir certificados autoassinados e gerar solicitações para a emissão de certificados de cliente. Esses parâmetros estão na seção [req_distinguished_name]

    O parâmetro com o postfix _default é o valor padrão. Um exemplo:

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

    Quando o sistema solicitar que você insira o parâmetro countryName , ele indicará entre colchetes que deixará o valor AU por padrão.


    Isso completa a configuração da configuração do OpenSSL. Resta indicar ao OpenSSL que é necessário usá-lo. Para fazer isso, configure a variável de ambiente OPENSSL_CONF:

     export OPENSSL_CONF=/path/to/your/openssl.cnf 
  3. Criamos uma estrutura de diretórios onde as informações sobre nossa CA serão armazenadas.
    Para fazer isso, vá para o diretório criado com o openssl.cnf recém-editado e execute as seguintes etapas:

    a) crie subdiretórios nele:

    demoCA
    demoCA / privado
    demoCA / newcerts

    Nota: o nome da demoCA está escrito na seção [CA_default] do arquivo openssl.cnf . Você pode alterá-lo (na etapa 2) e depois trabalhar com ele em vez do demoCA.

    b) no diretório demoCA, crie um arquivo index.txt vazio e um arquivo serial , que abrimos com um editor de texto e escrevemos a linha 01. Esse é o contador de certificados emitidos. Após a emissão de cada próximo certificado, o valor nesse arquivo aumenta em um.
  4. Como opção, formatamos nosso token usando o utilitário rtAdmin Agora, tudo está pronto para a implantação da CA.

    O algoritmo de ação é amplamente simples:

    a) emitimos o certificado raiz do centro de certificação usando o algoritmo GOST:

    • gerar uma chave privada para emitir um certificado de CA autoassinado
    • gerar um certificado X509 autoassinado usando a chave gerada

    b) em cada um dos tokens USB

    • gerar um par de chaves (o chamado contêiner de chave privada)
    • gerar uma solicitação de assinatura de certificado usando a chave do token gerada
    • emitir um certificado para esta solicitação
    • salve o certificado no token no contêiner de chave privada

    A seguir, é apresentada uma implementação desse algoritmo para um único token:

    Geração de chave privada para certificado CA (usamos o algoritmo GOST):

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

    Emitimos um certificado de CA autoassinado:

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

    Observe: indicamos na linha de comando que é necessário usar as extensões v3_ca na configuração openssl_cnf. É aí que é a nossa CA. Validade de 10 anos. Uma coisa comum para a CA. Mas mais é possível.

    No processo de emissão de um certificado, o sistema solicitará que você insira os valores dos parâmetros que estão na seção [req_distinguished_name] do nosso arquivo openssl.cnf

    Agora começamos as operações de token. Se o token for novo ou formatado com valores padrão, o PIN do usuário será 12345678. Prossigo com a suposição de que é exatamente isso. Caso contrário, você deve especificar o PIN do usuário correto e, geralmente, tentar garantir que, nos exemplos abaixo, os nomes dos objetos já existentes no token não se sobreponham aos inseridos.

    Primeiro de tudo, vamos gerar um par de chaves. O OpenSSL não pode executar esta operação no Rutoken, portanto, usaremos o utilitário pkcs11-tool do pacote OpenSC:

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

    Nota importante: especificamos o ID 303030303031. A cada dois dígitos desse ID nada mais é do que o código ASCII dos caracteres “0” e “1”, respectivamente. Para operações com OpenSSL, será semelhante a "id = 000001"

    Gere uma solicitação de certificado:

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

    Se tudo foi feito corretamente, o sistema

    • solicitar um PIN
    • solicitará os parâmetros do nome do certificado (na seção [req_distinguished_name] )
    • emitirá um arquivo de solicitação de assinatura de certificado

    Usando essa solicitação, assinamos um certificado de cliente ( no exemplo, o certificado é válido por 1825 dias. É importante que esse período não exceda o período de validade do seu certificado raiz ):

     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 

    O sistema exibirá o certificado, perguntará sobre a decisão de assiná-lo (responda “y”) e sobre a decisão de salvar o novo certificado (responda novamente “y”).

    Salvamos o certificado recebido para o token:

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

    Só isso.

    Testando o "milagre" criado. Para isso, assinamos e verificamos a assinatura da frase "Olá, mundo!":

     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 

    Se tudo for feito corretamente, o sistema solicitará um PIN, assinará a mensagem, verificará a assinatura e, se for bem-sucedido, exibirá a mensagem original e o resultado da verificação ("êxito")

    Observação . Retornando à tarefa de título e assinando usando o plug-in, deve-se observar que, por padrão, o plug-in fornece o resultado da assinatura não no formato PEM, mas no formato DER, codificado em base64. Portanto, para verificar a assinatura, você deve primeiro decodificar a partir da base64 e, ao marcar, especificar o formato DER de entrada.

    Boa sorte

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


All Articles