Clevis é uma estrutura conectável para descriptografia automatizada. Ele pode ser usado para fornecer descriptografia automatizada de dados ou até mesmo desbloqueio automatizado de volumes LUKS.
Como é isso? Bem, o primeiro passo é criptografar alguns dados. Fazemos isso com um comando simples:
$ clevis encrypt PIN CONFIG < PLAINTEXT > CIPHERTEXT.jwe
Este comando utiliza texto simples na entrada padrão e produz um objeto JWE criptografado na saída padrão. Além do texto simples, precisamos especificar dois parâmetros de entrada adicionais.
Primeiro, é o alfinete. Na terminologia clevis, um pin é um plugin que implementa a descriptografia automatizada. Simplesmente passamos o nome de um pin aqui.
Em segundo lugar, está a configuração. A configuração é um objeto JSON que será passado diretamente para o pin. Ele contém todas as configurações necessárias para realizar a criptografia e configurar a descriptografia automatizada.
Para descriptografar nosso JWE, simplesmente realizamos o seguinte:
$ clevis decrypt < CIPHERTEXT.jwe > PLAINTEXT
Observe que nenhuma entrada ou interação adicional é necessária para o comando decrypt. Vejamos alguns exemplos mais concretos.
Tang é uma implementação de servidor que fornece serviços de ligação criptográfica sem a necessidade de depósito. Clevis tem total apoio a Tang. Aqui está um exemplo de como usar Clevis com Tang:
$ echo hi | clevis encrypt tang ' {"url": "http://tang.local"} ' > hi.jwe
The advertisement is signed with the following keys:
kWwirxc5PhkFIH0yE28nc-EvjDY
Do you wish to trust the advertisement ? [yN] y
Neste exemplo, criptografamos a mensagem “oi” usando o pin Tang. O único parâmetro necessário neste caso é a URL do servidor Tang. Durante o processo de criptografia, o PIN Tang solicita o anúncio da chave do servidor e pede que você confie nas chaves. Isso funciona de forma semelhante ao SSH.
Alternativamente, você pode carregar manualmente o anúncio usando o parâmetro adv
. Este parâmetro usa uma string que faz referência ao arquivo onde o anúncio está armazenado ou ao conteúdo JSON do próprio anúncio. Quando o anúncio é especificado manualmente desta forma, Clevis presume que o anúncio é confiável.
Clevis fornece suporte para criptografar uma chave em um chip Trusted Platform Module 2.0 (TPM2). A chave aleatória criptograficamente forte usada para criptografia é criptografada usando o chip TPM2 e descriptografada usando TPM2 no momento da descriptografia para permitir que a manilha descriptografe o segredo armazenado no JWE.
Por exemplo:
$ echo hi | clevis encrypt tpm2 ' {} ' > hi.jwe
Clevis armazena as chaves públicas e privadas da chave criptografada no objeto JWE, para que possam ser obtidas na descriptografia para revelar a chave criptografada usando o TPM2.
Clevis pode desempenhar a função de um aplicativo PKCS#11, conforme descrito no RFC 7512: O esquema URI PKCS#11.
O protocolo PKCS#11 determina que um PIN (Personal Identity Number) deve ser configurado no dispositivo de hardware para que o processo de desbloqueio seja bem-sucedido. Clevis permitirá que os usuários desbloqueiem um disco criptografado específico e fornecerá uma maneira de obter o PIN. Haverá duas possibilidades:
1 - Forneça o PIN no momento da inicialização: Neste primeiro caso, o Clevis detectará o dispositivo PKCS#11 e solicitará seu PIN. Caso o PIN esteja errado, o Clevis solicitará o PIN novamente. É de responsabilidade do usuário estar atento ao possível bloqueio/bloco do dispositivo caso o PIN seja desconhecido.
2 - Forneça o PIN no momento da configuração do Clevis: Neste segundo caso o Clevis será configurado com o valor do PIN.
Inicialmente, o RFC7512 define um mecanismo para especificar um tipo especial de URI (o URI pkcs11
), que permite identificar tanto um dispositivo quanto as informações necessárias para que ele seja desbloqueado. Atenção especial merece os parâmetros pin-value
, que permitem especificar o valor do PIN ou a localização do PIN respectivamente. Clevis compreenderá, inicialmente, o parâmetro 'pin-value'. Abaixo você pode encontrar um exemplo de URIs PKCS#11 usando o parâmetro anterior:
pin-value
definido: pkcs11:token=Software%20PKCS%2311%20softtoken;manufacturer=Snake%20Oil,%20Inc.?pin-value=the-pin
Na próxima seção são fornecidos exemplos de configuração do Clevis, para que fique claro quais são as diferentes opções para um dispositivo PKCS#11 ser vinculado a um disco criptografado.
Clevis fornecerá um mecanismo para o usuário vincular um dispositivo PKCS#11 específico a um dispositivo criptografado. O nome do novo pin do Clevis será pkcs11
, e a forma de configurá-lo será a mesma que é usada atualmente:
$ clevis luks bind -h
Usage: clevis luks bind [-y] [-f] [-s SLT] [-k KEY] [-t TOKEN_ID] [-e EXISTING_TOKEN_ID] -d DEV PIN CFG
Como primeiro exemplo, um usuário pode fornecer as informações do dispositivo especificando seu URI para Clevis:
$ clevis luks bind -d /dev/sda1 pkcs11 '{"uri": "pkcs11:model=PKCS%2315%20emulated;manufacturer=piv_II;
serial=0a35ba26b062b9c5;token=clevis;id=%02;object=Encryption%20Key"}'
Uma opção adicional é fornecer à Clevis uma configuração para que o primeiro dispositivo PKCS#11 encontrado pela Clevis seja vinculado. Para fazer isso, um URI vazio pode ser fornecido conforme mostrado abaixo:
$ clevis luks bind -d /dev/sda1 pkcs11 '{"uri": "pkcs11:"}'
Um comando de configuração ainda mais curto, equivalente ao anterior, é mostrado abaixo:
$ clevis luks bind -d /dev/sda1 pkcs11 '{}'
Neste caso, a Clevis será responsável pela detecção do dispositivo e, caso nenhum dispositivo seja encontrado, será responsável por descartar o erro correspondente.
Deve ser esclarecido que fornecer um URI vazio fará com que Clevis solicite também a seleção de uma das chaves disponíveis correspondentes no token para evitar criptografia acidental com chaves indesejadas.
Um caminho de módulo pode ser fornecido ao Clevis, para que ele use esse módulo para acessar um dispositivo. Isso só é necessário caso a placa não seja suportada pelo software Clevis subjacente (OpenSC). Por esse motivo, o campo do caminho do módulo é totalmente opcional. Para fornecer a localização do módulo, o usuário pode fornecer o "module-path" para a configuração "uri" do Clevis:
$ clevis-luks-bind -d /dev/sda1 pkcs11 '{"uri": "pkcs11:model=PKCS%2315%20emulated;manufacturer=piv_II;
serial=0a35ba26b062b9c5;token=clevis;id=%02;object=Encryption%20Key?
module-path=/usr/local/lib64/libmypkcs11.so"}'
Assim como acontece com o restante dos dispositivos, os discos criptografados que foram vinculados a um dispositivo PKCS#11 podem ser verificados com o comando clevis luks list
:
$ clevis luks list -d /dev/sda1
1: pkcs11 '{"uri": "pkcs11:model=PKCS%2315%20emulated;manufacturer=piv_II;
serial=0a35ba26b062b9c5;token=clevis;id=%02;object=Encryption%20Key?
module-path=/usr/local/lib64/libmypkcs11.so"}'
Na primeira fase de desenvolvimento, Clevis será usado no topo do OpenSC para fornecer funcionalidade PKCS#11. OpenSC, e, em particular, pkcs11-tool
, oferece uma opção para indicar o mecanismo a ser usado para descriptografia. Para fins de teste, algumas bibliotecas, como SoftHSM), não funcionam com o mecanismo padrão pkcs11-tool
, portanto, é necessário fornecer um mecanismo específico para uso. Por este motivo, o Clevis pode ser fornecido com o mecanismo a ser utilizado, caso o padrão, RSA-PKCS-OAEP
, não seja válido:
$ clevis luks bind -d /dev/sda1 pkcs11 '{"uri": "pkcs11:", "mechanism":"RSA-PKCS"}'
Para verificar os mecanismos disponíveis para um token específico, o comando pkcs11-tool -M
pode ser usado:
$ pkcs11-tool -M
Using slot 0 with a present token (0x0)
Supported mechanisms:
SHA-1, digest
...
SHA512, digest
MD5, digest
...
RSA-PKCS-KEY-PAIR-GEN, keySize={2048,4096}, generate_key_pair
Neste momento, apenas os mecanismos RSA são suportados pela Clevis. Devido a uma limitação do restante dos algoritmos, nenhum outro algoritmo criptográfico assimétrico pode fazer criptografia facilmente. O ECC suporta apenas assinaturas e derivação de chaves, mas não criptografia. A operação de criptografia pode ser construída de alguma forma a partir da derivação da chave, mas não é uma operação simples.
Deve-se ressaltar que o mecanismo RSA-PKCS (preenchimento PKCS#1.5 para criptografia) é considerado não seguro e é fornecido principalmente para compatibilidade, mas não é recomendado seu uso em produção.
Clevis permitirá especificar o slot onde um dispositivo PKCS#11 está localizado através dos parâmetros fornecidos ao URI:
$ clevis luks bind -d /dev/sda1 pkcs11 '{"uri": "pkcs11:slot-id=0"}'
Deve-se esclarecer que fornecer apenas as informações do slot fará com que Clevis adivinhe uma das chaves disponíveis que correspondam ao token do slot selecionado, o que pode causar criptografia acidental com chaves indesejadas. Não é recomendado usar slot como seletor de dispositivo, pois o ID do slot é um número que não tem garantia de estabilidade nas inicializações do módulo PKCS#11 . No entanto, existem certas bibliotecas e módulos que fornecem identificadores de slot estáveis, para que possam ser usados nesses casos específicos.
Existem duas opções melhores para distinguir entre diferentes dispositivos PKCS#11:
1 - Configuração de vários dispositivos com objeto de chave pública ( recomendado ):
Com versões recentes do OpenSC
(da versão OpenSC 0.26.0) em diante, pkcs11-tool
, que é usado por Clevis para lidar com a maioria dos comandos PKCS#11, o URI PKCS#11 é despejado tanto para os tokens quanto para os objetos de um token específico:
$ pkcs11-tool -L | grep uri
uri : pkcs11:model=PKCS%2315%20emulated;manufacturer=piv_II;serial=42facd1f749ece7f;token=clevis
uri : pkcs11:model=PKCS%2315%20emulated;manufacturer=OpenPGP%20project;serial=000f06080f4f;token=OpenPGP%20card%20%28User%20PIN%29
$ pkcs11-tool -O --slot-index 1 --type pubkey | grep uri
ising slot 0 with a present token (0x0)
uri: pkcs11:model=PKCS%2315%20emulated;manufacturer=OpenPGP%20project;serial=000f06080f4f;token=OpenPGP%20card%20%28User%20PIN%29;id=%03;object=Authentication%20key;type=public
Nestes casos específicos, quando existem vários dispositivos PKCS#11, selecione a chave pública do dispositivo específico e vincule-a ao Clevis:
$ clevis luks bind -d /dev/sda pkcs11 '{"uri":"pkcs11:model=PKCS%2315%20emulated;manufacturer=OpenPGP%20project;serial=000f06080f4f;token=OpenPGP%20card%20%28User%20PIN%29;id=%03;object=Authentication%20key;type=public"}'
Caso você esteja usando module-path, você terá que usar aquele retornado ao fornecer a opção --module:
$ pkcs11-tool --module /usr/lib64/libykcs11.so -O --type pubkey | grep uri
/usr/local/bin/pkcs11-tool.manual --module /usr/lib64/libykcs11.so -O --type pubkey | grep uri
Using slot 0 with a present token (0x0)
uri: pkcs11:model=YubiKey%20YK5;manufacturer=Yubico%20%28www.yubico.com%29;serial=28083311;token=YubiKey%20PIV%20%2328083311;id=%03;object=Public%20key%20for%20Key%20Management;type=public
uri: pkcs11:model=YubiKey%20YK5;manufacturer=Yubico%20%28www.yubico.com%29;serial=28083311;token=YubiKey%20PIV%20%2328083311;id=%19;object=Public%20key%20for%20PIV%20Attestation;type=public
$ clevis luks bind -d /dev/sda pkcs11 '{"uri":"pkcs11:model=YubiKey%20YK5;manufacturer=Yubico%20%28www.yubico.com%29;serial=28083311;token=YubiKey%20PIV%20%2328083311;id=%03;object=Public%20key%20for%20Key%20Management;type=public;module-path=/usr/lib64/libykcs11.so"}'
2 - Configuração multi-dispositivo com especificação serial + token:
Para versões onde pkcs11-tool
não despeja o URI para os tokens/objects , a identificação específica será "tentada" pela Clevis usando o par serial
do dispositivo + token label
. Neste tipo de cenários, a identificação pode ser realizada com estes dois parâmetros, embora model
deva ser fornecido também para facilitar a informação do Clevis sobre o dispositivo ao solicitar o PIN:
# pkcs11-tool -L | grep "token label|serial"
token label : OpenPGP card (User PIN)
serial num : 42facd1f749ece7f
$ clevis luks bind -d /dev/sda pkcs11 '{"uri":"pkcs11:model=PKCS%2315%20emulated;serial=000f06080f4f;token=OpenPGP%20card%20%28User%20PIN%29"}'
Lembre-se de que os caracteres especiais devem ser definidos no modo percentual, conforme definido em RFC 7512: O esquema URI PKCS#11.
Para instalação e configuração do recurso manilha PKCS#11, os próximos passos devem ser seguidos:
1 - Instale as dependências necessárias do Clevis, incluindo dependências PKCS#11:
$ sudo dnf install -y opensc pcsc-lite openssl socat
2 - O dispositivo PKCS11 deve estar acessível pela “pkcs11-tool”:
$ pkcs11-tool -L
pkcs11-tool -L
Available slots:
Slot 0 (0x0): Yubico YubiKey OTP+CCID 00 00
token label : clevis
...
uri : pkcs11:model=PKCS%2315%20emulated;manufacturer=piv_II;serial=42facd1f749ece7f;token=clevis
3 - Configure o dispositivo para vincular à manilha:
$ sudo clevis luks bind -d /dev/sda5 pkcs11 '{"uri":"pkcs11:"}'
Caso seja necessário fornecer o módulo a ser utilizado, isso pode ser feito através do parâmetro URI module-path
:
$ sudo clevis luks bind -d /dev/sda5 pkcs11 '{"uri":"pkcs11:module-path=/usr/lib64/libykcs11.so.2"}'
4 - Habilite a unidade clevis-luks-pkcs11-askpass.socket:
$ sudo systemctl enable --now clevis-luks-pkcs11-askpass.socket
5 - Configuração do /etc/crypttab:
Para que o recurso PKCS#11 funcione adequadamente, o arquivo /etc/crypttab
deve ser configurado para que o systemd use um soquete AF_UNIX para aguardar a frase-chave que desbloqueará o disco e não para avisá-la através do console.
O arquivo da unidade Clevis PKCS#11 configurará um soquete no caminho /run/systemd/clevis-pkcs11.sock
para enviar e receber informações sobre o desbloqueio do disco. Para discos que serão desbloqueados através do pino PKCS#11 Clevis, esse arquivo de soquete deve ser configurado como arquivo de chave. Portanto, a próxima alteração deve ser introduzida em /etc/crypttab
para que o desbloqueio ocorra:
$ sudo diff -Nuar /etc/crypttab.ori /etc/crypttab
--- /etc/crypttab.ori 2024-07-04 10:46:16.295073739 +0200
+++ /etc/crypttab 2024-07-03 17:14:27.764743860 +0200
@@ -1 +1,2 @@
-luks-6e38d5e1-7f83-43cc-819a-7416bcbf9f84 UUID=6e38d5e1-7f83-43cc-819a-7416bcbf9f84 - -
+luks-6e38d5e1-7f83-43cc-819a-7416bcbf9f84 UUID=6e38d5e1-7f83-43cc-819a-7416bcbf9f84 /run/systemd/clevis-pkcs11.sock keyfile-timeout=30s
É altamente recomendável definir uma opção keyfile-timeout
para configurar um mecanismo de fall-through caso ocorra algum erro de desbloqueio e a senha seja necessária para ser inserida manualmente por meio do console.
6 - Reinicie e teste:
O sistema deve inicializar e solicitar o PIN do dispositivo PKCS#11 e descriptografar o disco criptografado configurado correspondente somente caso o PIN esteja correto.
7 - Caso nenhum processo de inicialização precise ser testado, criptografe e descriptografe com o próximo comando (observe que é necessário fornecer o valor do PIN para que funcione adequadamente) e verifique se a criptografia/descriptografia de uma string pode ser realizada com este one-liner , e nenhum erro ocorre:
$ echo "top secret" | clevis encrypt pkcs11 '{"uri":"pkcs11:module-path=/usr/lib64/libykcs11.so.2?pin-value=123456"}' | clevis decrypt
A string top secret
deve ser retornada
Clevis fornece uma maneira de misturar pinos para fornecer políticas de desbloqueio sofisticadas. Isso é feito usando um algoritmo chamado Shamir Secret Sharing (SSS).
SSS é um esquema de limite. Ele cria uma chave e a divide em várias partes. Cada parte é criptografada usando outro pino (possivelmente até SSS recursivamente). Além disso, você define o limite t
. Se pelo menos t
peças puderem ser descriptografadas, a chave de criptografia poderá ser recuperada e a descriptografia poderá ser bem-sucedida.
Aqui está um exemplo onde usamos o pino SSS com os pinos Tang e TPM2:
$ echo hi | clevis encrypt sss
' {"t": 2, "pins": {"tpm2": {"pcr_ids": "0"}, "tang": {"url": "http://tang.local"}}} '
> hi.jwe
No exemplo acima, definimos dois pinos filhos e temos um limite de 2. Isso significa que durante a descriptografia ambos os pinos filhos devem ser bem-sucedidos para que o próprio SSS seja bem-sucedido.
Aqui está outro exemplo onde usamos apenas o pino Tang:
$ echo hi | clevis encrypt sss
' {"t": 1, "pins": {"tang": [{"url": "http://server1.local/key"}, {"url": "http://server2.local/key"}]}} '
> hi.jwe
Neste exemplo, definimos duas instâncias filhas do pino Tang - cada uma com sua própria configuração. Como temos um limite de 1, se alguma das instâncias do pino Tang for bem-sucedida durante a descriptografia, o SSS será bem-sucedido.
Clevis pode ser usado para vincular um volume LUKS usando um alfinete para que ele possa ser desbloqueado automaticamente.
Como isso funciona é bastante simples. Geramos uma nova chave criptograficamente forte. Esta chave é adicionada ao LUKS como uma senha adicional. Em seguida, criptografamos essa chave usando Clevis e armazenamos o JWE de saída dentro do cabeçalho LUKS usando LUKSMeta.
Aqui está um exemplo onde vinculamos /dev/sda1
usando o pino Tang:
$ sudo clevis luks bind -d /dev/sda1 tang ' {"url": "http://tang.local"} '
The advertisement is signed with the following keys:
kWwirxc5PhkFIH0yE28nc-EvjDY
Do you wish to trust the advertisement ? [yN] y
Enter existing LUKS password:
Após a conclusão bem-sucedida deste processo de vinculação, o disco pode ser desbloqueado usando um dos desbloqueadores fornecidos.
Se você quiser usar o desbloqueio baseado em rede, você precisará especificar rd.neednet=1
como argumento do kernel ou usar --hostonly-cmdline
ao criar com dracut.
Se você estiver usando Tang com TLS (exemplo: '{"url": "https://tang.remote"}'
), a pasta /etc/ssl
deve ser incluída na imagem initramfs, --include /etc/ssl /etc/ssl --force
ao criar com dracut.
O desbloqueador Dracut tenta desbloquear volumes automaticamente durante a inicialização inicial. Isso permite a criptografia automatizada do volume raiz. Ativar o desbloqueador Dracut é fácil. Basta reconstruir seu initramfs após instalar o Clevis:
$ sudo dracut -f
Após a reinicialização, você será solicitado a desbloquear o volume usando uma senha. Em segundo plano, o Clevis tentará desbloquear o volume automaticamente. Se for bem-sucedido, a solicitação de senha será cancelada e a inicialização continuará.
Ao usar o Clevis com initramfs-tools, para reconstruir seu initramfs você precisará executar:
sudo update-initramfs -u -k ' all '
Após a reinicialização, ele se comportará exatamente como se estivesse usando o Dracut.
Nosso desbloqueador UDisks2 é executado em sua sessão de desktop. Você não precisará ativá-lo manualmente; basta instalar o desbloqueador Clevis UDisks2 e reiniciar sua sessão de desktop. O desbloqueador deve ser iniciado automaticamente.
Este desbloqueador funciona quase exatamente da mesma forma que o desbloqueador Dracut. Se você inserir um dispositivo de armazenamento removível vinculado ao Clevis, tentaremos desbloqueá-lo automaticamente em paralelo com uma solicitação de senha no desktop. Se o desbloqueio automático for bem-sucedido, a solicitação de senha será ignorada sem intervenção do usuário.
Um dispositivo LUKS vinculado a uma política Clevis também pode ser desbloqueado usando o comando clevis luks unlock.
$ sudo clevis luks unlock -d /dev/sda1
Os volumes LUKS podem ser desvinculados usando o comando clevis luks unbind. Por exemplo:
$ sudo clevis luks unbind -d /dev/sda1 -s 1
Os pinos vinculados a um determinado volume LUKS podem ser listados usando o comando clevis luks list. Por exemplo:
$ sudo clevis luks list -d /dev/sda1
Por favor, não instale o Clevis diretamente. Em vez disso, use os pacotes de sua distribuição preferida.
Este comando instala os comandos principais do Clevis, o desbloqueador Dracut e o desbloqueador UDisks2, respectivamente.
$ sudo dnf install clevis clevis-dracut clevis-udisks2
Conforme observado na seção anterior, sugere-se não instalar o Clevis diretamente . Porém, caso não existam pacotes Clevis para sua distribuição Linux, os passos para compilar e instalar manualmente o Clevis são os seguintes:
$ wget https://github.com/latchset/clevis/releases/download/v21/clevis-21.tar.xz
$ tar Jxvf clevis-21.tar.xz
$ cd clevis-21
$ mkdir build
$ cd build
meson
para configurar a compilação: $ meson setup ..
ninja
: $ ninja
ninja install
(você precisará de permissões de root para isso): $ sudo ninja install