Trusted Execution Environment no exemplo da Intel SGX. Princípios básicos em termos simples. "Olá Mundo!"

Este artigo destina-se principalmente a um especialista novato que é apenas

começou a pesquisar métodos e maneiras de garantir a segurança da informação do código do programa executável. Mais cedo ou mais tarde, todos os desenvolvedores de software e engenheiros de sistema enfrentam tal tarefa, que aconteceu em um dos projetos da Altiriks Systems, dentro da estrutura da qual era necessário implementar a execução segura do código do programa em um ambiente desprotegido condicionalmente. Para tanto, além dos métodos e meios já conhecidos e descritos de proteção da informação, foi escolhida a tecnologia Trusted Execution Environment (TEE), raramente utilizada em projetos russos, ou, falando em russo, a tecnologia de ambientes de execução confiáveis. Especificamente, neste artigo, decidimos descrever um exemplo prático do uso de enclaves de processador Intel para um ambiente de execução de código confiável (Intel Software Guard Extensions ou SGX).



Os tempos de execução confiáveis ​​não são suportados apenas por processadores de um determinado fabricante. Além disso, o TEE é compatível com vários processadores AMD (Secure Execution Environment, Secure Technology), processadores ARM (TrustZone) e processadores RISC-V. Além disso, o TEE é suportado por modernos mainframes IBM Z. Escolhemos Intel SGX como nosso exemplo porque acreditamos que, no momento em que este artigo foi escrito (verão de 2020), os processadores Intel eram os mais populares e disponíveis para iniciantes no espaço pós-soviético. Para obter uma lista completa dos modelos de processadores Intel que suportam Intel SGX, visite o site da Intel em especificações de produto Intel (ARK) selecionando a tecnologia apropriada para pesquisa. E sim, talvez aproveite as emulações do Intel SGX para fins educacionais ou de pesquisa.Trabalhar com várias dessas emulações revelou uma série de dificuldades em configurá-las. Você também precisa entender que para projetos de "combate" reais, nenhuma emulação de tecnologia baseada na funcionalidade do aparelho, é claro, é aceitável.



Qualquer um de seus comentários, principalmente com comentários e acréscimos de especialistas que já têm experiência no uso de TEE em seus projetos, ou com dúvidas daqueles que estão apenas começando a mergulhar nesta tecnologia, contribuirá para uma divulgação mais detalhada deste tópico nos próximos artigos. Desde já, obrigado!



Introdução



A principal pergunta que fazemos no início da jornada de exploração de ambientes de tempo de execução confiáveis ​​é: podemos confiar nos componentes de um sistema de computador? E se pudermos, como? Os desenvolvedores, e em particular os engenheiros da Intel, dão uma resposta inequívoca a esta pergunta: ninguém exceto a própria Intel. O que isto significa? Proponho entender isso com mais detalhes.



Anéis de privilégio



Para fins de segurança, os componentes do sistema de qualquer computador são divididos em níveis de privilégio. Todos os sistemas modernos baseados em processadores Intel e não apenas possuem um sistema de anel de privilégios. De externo para interno, há uma expansão da autoridade para o código que está sendo processado pelo processador.





Toque número 3. O anel externo contém todos os aplicativos do usuário que usamos no computador no dia a dia, eles têm o nível de acesso mais baixo.

Toque nº 2 e nº 1. Os sistemas operacionais e drivers de dispositivo estão localizados nesses níveis.

Número de toque 0. Modo supervisor. É onde o kernel do sistema operacional (gerenciamento de periféricos, alocação de recursos entre processos) está localizado, bem como os drivers do sistema.

Toque número-1. Hypervisor. Responsável pela alocação de recursos caso vários sistemas operacionais estejam rodando no computador ao mesmo tempo, e também é responsável por isolá-los.

Número de toque-2.Modo de gerenciamento do sistema (SMM - Modo de gerenciamento do sistema). Gerencia a fonte de alimentação do sistema, gerencia placas de expansão.



Podemos formar cada vez mais anéis para limitar os poderes dos componentes da hierarquia, criando um sistema cada vez mais complexo e carregado. No entanto, isso apenas tornará o trabalho de um invasor mais fácil: quanto mais complexo for o sistema, mais fácil será encontrar vulnerabilidades nele. Mas como você pode fornecer uma camada extra de segurança onde você precisa? A resposta é uma palavra.



Enclaves



A principal tarefa de um invasor é obter um nível de privilégio que forneceria a ele acesso aos recursos de sistema necessários. Se esse for o segredo do aplicativo vítima, o aplicativo malicioso precisa exatamente do nível de acesso responsável por armazenar os segredos no sistema. Isso sugere a conclusão de que o gerenciamento dos segredos do aplicativo deve ser confiado ao anel mais interno, pois o acesso ali é o mais difícil de todos. No entanto, essa abordagem foi um tanto repensada. Agora, todos os segredos são armazenados no mesmo nível com os aplicativos do usuário, bem como o código que gerencia esses segredos sob uma condição: ninguém, absolutamente ninguém, exceto o processador, pode acessá-los. O programa e os dados são, por assim dizer, empacotados em um armazenamento, neste caso, esse armazenamento é chamado de enclave (Enclave - fechado, bloqueado),a chave da qual apenas o processador possui.





Aplicativos que funcionam em um ambiente confiável



Quanto mais simples o sistema, menos código ele contém, mais difícil é abri-lo com base em brechas de segurança (não estamos falando de sistemas fundamentalmente desprotegidos), obtemos um certo axioma: o código que trabalha com um segredo deve ser o mais simples e curto possível. Empacotar todo o código do programa em um enclave é impraticável, portanto, um aplicativo que usa enclaves deve ser dividido em duas partes: "confiável" e "não confiável". O confiável armazena enclaves (pode haver vários deles), e o não confiável armazena o código do programa principal.



A parte confiável é um conjunto de funções e procedimentos chamados ECALL (Enclave Call). A assinatura de tais funções deve ser escrita em um arquivo de cabeçalho especial e sua implementação no arquivo de código-fonte. Em geral, a abordagem é semelhante à que usamos para a escrita usual de cabeçalhos, no entanto, neste contexto, uma linguagem especial C-like EDL (Enclave Definition Language) é usada. Também é necessário escrever protótipos dessas funções que podem ser chamadas de dentro do enclave, tais funções são chamadas de OCALL (Chamada Externa). Os protótipos são escritos no mesmo cabeçalho em que as funções ECALL estão, e a implementação, ao contrário de ECALL, é escrita de acordo na parte não confiável do aplicativo.

Código confiável e não confiável são rigidamente vinculados pela certificação usando o protocolo Diffie-Hellman. O processador é responsável pelo procedimento de assinatura, onde fica armazenada a chave de troca de informações, que é atualizada sempre que o sistema é reinicializado. O conteúdo dos enclaves é armazenado na memória compartilhada usada pelos aplicativos do usuário, mas o armazenamento é criptografado. Apenas o processador pode descriptografar o conteúdo. Em um mundo idealizado, onde o código do enclave é escrito sem um único bug e todo o hardware funciona exatamente como o fabricante pretendia e nada mais, obteríamos um sistema universal e completamente seguro. A principal vantagem deste sistema é a execução da parte secreta no mesmo processador onde todos os outros programas, inclusive os programas do usuário, são executados.



No entanto, nos últimos anos, um grande número de vulnerabilidades de microarquitetura de processadores modernos apareceu diante de um grande público, permitindo acesso ao interior do enclave: Foreshadow (vulnerabilidade da classe Specter), SGAxe, Zombieload, CacheOut e muitos outros. Não há garantia de que esta lista não será substituída por outra vulnerabilidade de hardware séria, cuja correção de software não pode ser chamada de "patch" de software. Talvez vivamos para ver o tempo em que uma arquitetura de processador completamente nova será apresentada ao mundo, na qual todas as deficiências serão corrigidas, mas por enquanto, vale a pena falar sobre o que temos em mãos. E à mão temos uma ferramenta versátil e poderosa que aumenta drasticamente a segurança dos sistemas atuais. Levantando muitoque seja implementado de uma forma ou de outra em bilhões de dispositivos em todo o mundo: de relógios inteligentes, smartphones a enormes clusters de computação.



Olá Mundo!



Vamos passar da teoria à prática. Vamos escrever um pequeno programa que implementa a tarefa já canônica: imprima a string "Hello world!" Nessa interpretação, indicaremos também o local de onde a mensagem será enviada.



Primeiro você precisa baixar e instalar o SDK para trabalhar com SGX do site oficial. Para fazer o download, você precisa seguir um procedimento simples de registro. No estágio de instalação, você será solicitado a integrar o pacote de desenvolvimento à versão do VS disponível em seu computador. Faça isso. Tudo está pronto para a implementação com sucesso do primeiro projeto usando SGX.





Inicie o VS e crie um projeto Intel SGX.





Escolhemos um nome para o projeto e para a solução e aguardamos o “próximo”.



A seguir, será solicitado que você selecione uma configuração de projeto, não altere nada, deixe os valores que foram originalmente propostos.







Em seguida, adicione outro projeto à solução criada: um aplicativo de console C ++ normal.

Como resultado, a seguinte imagem deve aparecer na caixa de diálogo dos projetos:







Em seguida, você precisa vincular o enclave à parte não confiável. Clique com o botão direito do mouse no projeto "Parte não confiável".







Em seguida, você precisa alterar algumas propriedades dos projetos.



imagem






Isso deve ser feito para que o programa funcione corretamente. Repetimos as etapas para ambos os projetos.



Também é necessário indicar o projeto principal nas propriedades da solução.





É isso, nosso programa está pronto para ser implementado.



Este programa terá 3 arquivos com os quais trabalharemos: Enclave.edl (o mesmo cabeçalho), Enclave.cpp (a implementação de ECALL está explicitada), Untrusted Part.cpp (o arquivo de projeto principal é a parte não confiável). Vamos colocar o



seguinte código em arquivos:



Untusted Part.cpp:



#define ENCLAVE_FILE "Enclave.signed.dll" //,     

#include "sgx_urts.h" // ,           
#include "Enclave_u.h" //   
#include "stdio.h"

void print_string(char* buf) //OCALL     -   
{
	printf("ocall output: %s\n", buf);
}

int main()
{
	sgx_enclave_id_t eid; // id ,      ,    id
	sgx_status_t ret = SGX_SUCCESS; //        
	sgx_launch_token_t token = { 0 }; //    
	int updated = 0; //      
	const int BUF_LEN = 30; //  ,     

	ret = sgx_create_enclave(ENCLAVE_FILE, SGX_DEBUG_FLAG, &token, &updated, &eid, NULL); //  

	if (ret != SGX_SUCCESS)
	{
		printf("Failed to create enclave with error number: %#x\n", ret); //  
		return 0;
	}
	char buf[BUF_LEN]; //  ,      

	enclaveChat(eid, buf, BUF_LEN); // ECALL  

	printf("\noutput form main(): %s\n", buf); //  
}


Enclave.edl:



enclave {
    from "sgx_tstdc.edl" import *;

    trusted {
        /* define ECALLs here. */
        public void enclaveChat([out, size=len] char* str, size_t len);
        /*   ,    . OUT -   ,   
                , out     .
           ,          ,
                 .
        */
    };

    untrusted {
        /* define OCALLs here. */
        void print_string([in, string] char* buf); //  ,     
    };
};


Enclave.cpp:



#include "Enclave_t.h"

#include "sgx_trts.h"
#include <cstring>

void enclaveChat(char* str, size_t len)
{
	char* secret = "Hello from better place"; //   

	memcpy(str, secret, len); //   ,  

	print_string(secret); // OCALL-  
}


Pressione f7 - construir a solução e, em seguida, ctrl + f5 para executar.



Se você receber um erro como este:





certifique-se de que Intel SGX esteja habilitado no BIOS: Bios: Security / IntelSGX / Enabled.



Caso não houvesse erros, e na frente da tela do console, você via as seguintes linhas:





... parabéns, seu primeiro programa com a tecnologia Intel SGX está pronto. Espero que os comentários no código tenham sido abrangentes para compreensão, caso contrário, você sempre pode fazer perguntas aqui nos comentários ou em mensagens privadas.



All Articles