Inicialização segura no i.MX6
Ao desenvolver qualquer projeto para sistemas embarcados, o desenvolvedor deve resolver dois problemas adicionais:- Como proteger o firmware contra falsificação no produto;
- Como proteger o software da cópia.
Este artigo descreve como proteger o processador i.MX6 de alterar o carregador de inicialização no produto e complicar o processo de cópia do firmware.
Introdução
Proteger a propriedade intelectual, caso o projeto bare metal [1] ajude principalmente um complexo de hardware, presente no microcontrolador e externo. Exemplos são dados em um site respeitável [2] . Métodos de software adicionais, como [3] são usados, no entanto, são baseados no mecanismo de proteção desconhecido. Isso se deve ao baixo poder de computação dos dispositivos e ao inconveniente de implementar a geração dinâmica de firmware.Quando o SoC entra em jogo com sistemas operacionais como o Linux, a proteção precisa ser organizada simultaneamente em vários níveis:- Nível final da aplicação
- Nível do sistema operacional
- Nível do carregador de inicialização
No caso de obter acesso em qualquer um dos níveis, é fácil influenciar o software de outros níveis e fazer alterações nas interações entre níveis.Os exemplos mais simples: seu software instalado no Linux se comunica através do protocolo UART (por exemplo, através de / dev / ttyACM0) com um microcontrolador. Um invasor que obtém acesso ao sistema usa o mesmo recurso UART e repete pacotes enviados aleatoriamente. Ou, por exemplo, se o driver estiver embutido no kernel, o invasor recompila o kernel reescrevendo o código do driver UART de outra maneira. A aplicação final não sabe o que está acontecendo.
O que é inicialização segura e por que é necessário?
O primeiro nível de proteção do seu software no sistema de destino é a inicialização segura. A seguir, a inicialização segura é explicada para processadores da família i.MX6.A inicialização segura no i.MX6 é implementada por meio do High Assurance Boot (HAB) e pode executar duas funções:- modo de segurança
- download criptografado.
Neste artigo, descreverei o processo de garantir o carregamento seguro do processador. O I.MX6 também implementa um algoritmo que fornece criptografia para o carregador de inicialização. No entanto, seu uso requer a geração de um gerenciador de inicialização exclusivo para cada produto, pois utiliza uma função de criptografia exclusiva para cada processador. Este é um procedimento inconveniente na série, então não o descrevi. Se você tem algo a dizer sobre esse assunto, ficarei feliz em ouvir.A inicialização segura tenta garantir que o carregador de inicialização seja iniciado no seu produto, com o kernel que você carregou nele.
Sobre a definição que eu dei inicialização segura. A inicialização segura não impede que você copie o produto. Sim, isso torna o procedimento mais difícil, mas não muito. O carregador de inicialização não pode assinar todo o FS, portanto, não fornece proteção no nível do SO e no nível do aplicativo final. Tudo funciona de forma clássica: por meio de criptografia assimétrica. Vou descrever o processo nos dedos, que pode ser lido mais profundamente em [4]. O carregador de inicialização indica o script para o HAB, onde as áreas de memória assinadas são indicadas e onde está a assinatura digital. A chave pública está pré-localizada na memória do processador One time programable (OTP). Ao carregar, o script verifica a área de memória especificada usando a assinatura digital anexada e uma chave com fio. Se o teste falhar, o processador não inicia o download. A operação HAB também deve ser ativada definindo um pouco na região da memória OTP.Desvantagens da inicialização segura:- Se o HAB não estiver ativado, o firmware ainda será iniciado. Isso significa que, sem adicionar. métodos de proteção, seu firmware será executado em uma cópia do produto. Para impedir que isso aconteça, o carregador de inicialização deve ativar o HAB independentemente na inicialização. Mas, inserindo uma unidade flash USB em outro produto e esquecendo de atualizar a chave pública, você pode jogar fora o processador.
- Ao acessar a memória do processador, você pode copiar a chave pública, isso é suficiente para copiar o produto.
Implementação
Em geral, existem muitos artigos em inglês [5] [6] na Internet sobre o tópico de implementação, mas nenhum método proposto decolou de uma vez e os links para o software começaram a morrer, então decidi salvá-lo como um artigo principalmente para mim, quando Voltarei a esta questão no futuro.Primeiro você precisa baixar o seguinte software: ferramenta de assinatura de código [7] e os scripts necessários para gerar chaves e assinatura. No arquivo especificado, eu removi todos os utilitários e bibliotecas desnecessários, pois existem muitas coisas não utilizadas para nossa tarefa.Em seguida, você precisa gerar as chaves:cd ${CST_PATH}/release/keys
echo ${serial} > serial //8 ,
echo ${password} > key_pass.txt // ,
echo ${password} >> key_pass.txt //
./hab4_pki_tree.sh //
Do you want to use an existing CA key (y/n)?: n
Do you want to use Elliptic Curve Cryptography (y/n)?: n
Enter key length in bits for PKI tree: 4096
Enter PKI tree duration (years): 10
How many Super Root Keys should be generated? 4
Do you want the SRK certificates to have the CA flag set? (y/n)?: y
../linux64/bin/srktool -h 4 -t SRK_1_2_3_4_table.bin -e SRK_1_2_3_4_fuse.bin \
-d sha256 -c ./SRK1_sha256_4096_65537_v3_ca_crt.pem,\
./SRK2_sha256_4096_65537_v3_ca_crt.pem,./SRK3_sha256_4096_65537_v3_ca_crt.pem,\
./SRK4_sha256_4096_65537_v3_ca_crt.pem -f 1
O script de geração de chaves levanta as questões acima. Dei um exemplo de opções padrão. A resposta para eles determina como as chaves e parâmetros gerados das chaves geradas serão chamados. Considere com outros comandos. Em seguida, lemos a chave pública necessária para gravar no processador. Usaremos um script conveniente de [5] para isso .cd ${CST_PATH}/release/linux64/bin
./var-u-boot_fuse_commands.sh
fuse prog 3 0 0xFFFFFFFF // uboot.
fuse prog 3 1 0xFFFFFFFF //
fuse prog 3 2 0xFFFFFFFF // .
fuse prog 3 3 0xFFFFFFFF // - .
fuse prog 3 4 0xFFFFFFFF // .
fuse prog 3 5 0xFFFFFFFF //
fuse prog 3 6 0xFFFFFFFF //
fuse prog 3 7 0xFFFFFFFF //
Esta tarefa pode ser aplicada ao uboot com SPL integrado ou com SPL e uboot separados (versão rocko, por exemplo). Estou escrevendo um release para que você saiba onde eles são usados como padrão. Se você mesmo compilar o uboot, provavelmente o seu SPL será integrado ao uboot. Um ponto importante no carregador de inicialização defconfig é adicionar as seguintes opções:CONFIG_SECURE_BOOT=y
CONFIG_SYS_FSL_HAS_SEC=y
Essas opções ativam drivers para trabalhar com módulos de hardware. Tudo é como no menuconfig para Linux. Ao compilar o carregador de inicialização, use o modo detalhado (remova V = 1. A montagem com este parâmetro está escrita no guia. No entanto, eu mesmo a limpei). Nesse caso, informações sobre o endereço do ponto de entrada e outras coisas necessárias para gravar uma assinatura digital são adicionadas aos logs de compilação. Após a compilação, precisamos dos seguintes arquivos de saída:- u-boot-ivt.img
- u-boot-ivt.img.log
- SPL
- SPL.log
copie-os para $ {CST_PATH} / release / linux64 / bin. Em seguida, você precisa executar um script bastante simples.Descrição detalhada do procedimento de script(*.csf). , :
. , ( ).
:
Image Name: U-Boot 2019 // U-boot
Created: XXXXXX
Image Type: ARM U-Boot Firmware with HABv4 IVT (uncompressed)
Data Size: 339904 Bytes = 331.94 KiB = 0.32 MiB
Load Address: 17800000
Entry Point: 00000000
HAB Blocks: 0x177fffc0 0x0000 0x00051020
Image Type: Freescale IMX Boot Image // SPL
Image Ver: 2 (i.MX53/6/7 compatible)
Mode: DCD
Data Size: 61440 Bytes = 60.00 KiB = 0.06 MiB
Load Address: 00907420
Entry Point: 00908000
HAB Blocks: 00907400 00000000 0000cc00
DCD Blocks: 00910000 0000002c 00000004
«HAB Blocks». ,
cd ${CST_PATH}/release/linux64/bin
./cst --o u-boot_csf.bin --i u-boot.csf
cat u-boot-ivt.img u-boot_csf.bin > u-boot_signed.img
Tanto quanto me lembro no caso do SPL integrado, provavelmente tudo funcionará da mesma maneira, mas vale a pena conferir. Não me lembro agora e não comecei a compilar ao escrever este artigo.cd ${CST_PATH}/release/linux64/bin
SOC=mx6 ./var-som_sign_image.sh SPL u-boot-ivt.img
De acordo com os resultados do script, você obterá dois arquivos: SPL_signed, u-boot-ivt.img_signed, que deve ser gravado no disco do sistema de destino. Aplico um exemplo de script de gravação ao sistema de destino. Sem sudo, para não atirar acidentalmente na perna.dd if=SPL_signed of=${DEVICE(/dev/sd*)} bs=1K seek=1; sync
dd if=u-boot-ivt.img_signed of=${DEVICE(/dev/sd*)} bs=1K seek=69; sync
Depois de gravar em um meio em branco, você deve obter um gerenciador de inicialização sem um kernel que trava no console, pois ele não encontra o dtb e o kernel. No console, você pode verificar se o que você fez ou não realmente funciona. Na presença de evento - algo deu errado. Importante: se o gerenciador de inicialização for compilado sem o suporte ao HAB, também não haverá erros.hab_status
HAB Configuration: 0xf0, HAB State: 0x66
No HAB Events Found!
O último passo é ativar o HAB, a atenção é um comando único, não pode ser corrigido, portanto, tenha cuidadofuse prog 0 6 0x2
Conclusão
Não comecei a descrever o processo de integrar tudo isso ao yocto, mas tenho que guardar segredos. No entanto, isso é viável e não requer muito tempo.referência
[1] software embarcado com bare metal que roda diretamente no hardware sem nenhuma abstração na forma de sistemas operacionais[2] we.easyelectronics.ru/Soft/zaschita-ustroystva-ot-vzloma-i-kopirovaniya.html[3] ] habr.com/en/post/350602[4] HAB4_API.pdf em github.com/BMValeev/CST_TOOL[5] variwiki.com/index.php?title=High_Assurance_Boot[6] boundarydevices.com/high-assurance-boot -hab-dummies[7] github.com/BMValeev/CST_TOOL