Como assinar aplicativos para o macOS Catalina 10.15

imagem

[Nota trad .: traduzindo o post que causou ampla discussão sobre Habré, fiquei interessado nas novas regras para desenvolvedores de software introduzidas pela Apple. Este artigo fala sobre a experiência pessoal de dominar as regras com um dos desenvolvedores de jogos.]

1. Introdução


Na nova versão do macOS, a Apple fez alguns requisitos para aplicativos que costumavam ser recomendações: arquivos executáveis ​​de 64 bits, assinatura e reconhecimento de firma. Os aplicativos que não atendem a esses requisitos não serão mais lançados.

Isso é feito para proteger o trabalho dos usuários e impedir a disseminação de programas maliciosos, mas, ao mesmo tempo, torna a vida muito difícil, especialmente para as pessoas para quem o Mac não é a principal plataforma de desenvolvimento, mas que, no entanto, gostariam de iniciar ou continuar suportando o Mac. .

Isto é especialmente verdade para desenvolvedores de jogos que publicam jogos para Mac no Steam. Até mudanças recentes, os jogos lançados a partir do Steam não precisavam assinar e notarizar, mas agora devem obedecer às mesmas regras que todos os outros.

Acabei de descobrir como implementar esses requisitos para o meu jogo Airships: Conquer the Skies . Os dirigíveis funcionam em Java e, portanto, também requerem uma JVM, mas, em geral, tudo o mais será aplicável à maioria dos desenvolvedores.

Aqui está o que aprendi sobre como assinar e notarizar um aplicativo para Mac que não foi compilado diretamente pelo Xcode. Observe que as informações são obtidas em minha própria pesquisa e podem não ser 100% precisas. Perguntas e correções são bem-vindas.

Antecedentes


Este artigo discute assinatura e reconhecimento de firma. Obter o arquivo executável de 64 bits do programa é uma tarefa do seu compilador ou ambiente de desenvolvimento.

No macOS, os aplicativos geralmente são empacotados em pastas de pacote contendo o executável, além de recursos e metadados adicionais. Assinar um pacote significa criar uma soma de verificação criptográfica do conteúdo do pacote e, em seguida, criar uma assinatura criptográfica com um certificado que a Apple emite para o desenvolvedor. Uma assinatura é uma declaração de que você garante pessoalmente o comportamento correto do aplicativo. Se o conteúdo do pacote configurável for alterado, a soma de verificação será alterada e a assinatura deixará de corresponder a eles, avisando o sistema operacional que alterações não autorizadas foram feitas no pacote configurável.

A assinatura do aplicativo existe há muitos anos. Um pouco mais tarde, os pedidos também se tornaram necessários para notarizar. Notarização significa que você envia um aplicativo Apple assinado e a empresa realiza verificações adicionais e registra o aplicativo. Se o reconhecimento de firma for bem-sucedido, você "colará" o reconhecimento de firma em seu aplicativo, para que as máquinas offline sem acesso à Internet também possam garantir que o aplicativo tenha reconhecimento de firma.

Este é um tipo de metáfora para trabalhar com documentos em papel. O desenvolvedor coleta em um pacote todas as partes que compõem o aplicativo. Em seguida, ele cria uma lista de todos os elementos do pacote (soma de verificação) e assina essa lista (com uma assinatura digital), que cola no pacote. Em seguida, ele passa o pacote assinado ao notário Sr. Yablokov, que verifica se tudo está em ordem com o pacote e o registra. Ele entrega ao desenvolvedor um recibo que o grampeador anexa ao pacote. Ou seja, se o desenvolvedor disse que o aplicativo é seguro, e Yablokov também diz que é seguro, provavelmente é. E se uma pessoa má tentar alterar seu conteúdo, a lista de elementos do pacote deixará de corresponder a ele e o usuário saberá que não é necessário usá-lo.

Exigências


O que é necessário para assinar e notarizar o aplicativo:

  • Um computador Mac novo o suficiente para executar o Xcode 11, ou seja, novo o suficiente para executar o macOS 10.14.3. Se você ainda não instalou o Xcode, serão necessários 25 GB de espaço livre para a instalação.
  • Se você ainda não é um desenvolvedor oficial da Apple, é necessário fazer login na Apple ID e aproximadamente US $ 110 para ser membro.

Autenticação de dois fatores


Se você ainda não possui um, ative a autenticação de dois fatores para o seu ID Apple. Isso pode ser feito a partir de qualquer dispositivo i ou de um Mac. Em um Mac, acesse o painel de controle do iCloud nas configurações de Preferências do sistema. No topo, deve haver um painel sugerindo a ativação do 2FA.

Compra de associação


Faça login em https://developer.apple.com/ usando seu ID Apple e vá para a guia Associação. Compre ou atualize sua associação ao Apple Developer Program, se necessário. Observe que o processamento de uma compra leva algum tempo nos sistemas internos da Apple; portanto, se você não conseguir gerar certificados (veja abaixo), beba uma xícara de chá por um tempo e se acalme.

ID do aplicativo


Pode ser necessário registrar o ID do pacote de aplicativos no back-end do desenvolvedor. O ID do pacote configurável pode ser encontrado em YourApp.app/Contents/Info.plist. (Você pode abrir pacotes de aplicativos clicando com o botão direito do mouse neles e selecionando “Mostrar Conteúdo do Pacote.”). O identificador deve ser com.yourcompanyname.applicationname, por exemplo, meu jogo Aeronaves tem com.zarkonnen.airships.

Para registrar um ID, faça login em https://developer.apple.com/ , selecione “Certificados, IDs e perfis” no painel esquerdo e, em seguida, selecione “Identificadores” na página seguinte. Depois, você pode clicar no botão "+" para adicionar o identificador do aplicativo.

Senha do aplicativo


Para assinar na linha de comando, você precisará da senha do aplicativo, acesse https://appleid.apple.com/account/manage e gere-a.

Xcode e ferramentas


Instale o Xcode na App Store do Mac App. Em seguida, instale também as ferramentas de linha de comando do Xcode em https://developer.apple.com/download/more . Você precisa das Ferramentas de Linha de Comando do Xcode 11 ou da versão do Xcode que está usando.

Certificado


Inicie o Xcode, vá para Preferências, abra a guia Contas. Se necessário, adicione seu ID Apple à lista de contas. Em seguida, clique no botão "Gerenciar certificados ..." no canto inferior direito. Os certificados que você possui para assinar aplicativos são exibidos. Você precisa de um certificado "Developer ID Application"; se não estiver na lista, crie-o. Clique em "Concluído" e depois em "Download" na janela Preferências: Contas para baixar os certificados localmente.

Preparação da aplicação


Para que o aplicativo funcione corretamente no novo sistema, o arquivo executável e as bibliotecas devem ser de 64 bits.

Além disso, o Mac OS realiza uma operação chamada "translocação": por motivos de segurança, move o pacote de aplicativos em execução para um local aleatório. No caso do meu aplicativo, isso se manifestou no fato de que não foi possível encontrar os arquivos de dados localizados ao lado do pacote de aplicativos. Você pode obter o local inicial do pacote de aplicativos, mas resolvi o problema simplesmente colocando tudo no pacote.

Permissões (direitos)


Essas são permissões especiais adicionadas pelo desenvolvedor, juntamente com a assinatura de código, permitindo que os aplicativos assinados executem determinadas ações. Se você compilar o aplicativo usando o Xcode, ele fará tudo sozinho; caso contrário, você precisará criar um arquivo plist contendo todos os direitos necessários. Os arquivos Plist podem ser criados usando o Xcode, e em https://developer.apple.com/documentation/bundleresources/entitlements há uma lista de direitos.

Para criar um novo arquivo plist usando o Xcode, selecione "Novo arquivo" e clique em "Lista de propriedades" na lista exibida. Adicione os elementos com direitos necessários ao dicionário raiz; eles têm o significado booleano: SIM.


No caso do meu jogo, como ele é escrito em Java, eu precisava das seguintes permissões para a JVM funcionar: com.apple.security.cs.allow-jit, com.apple.security.cs.allow-unsigned-executable-memory, com. proteção da página executável da apple.security.cs.disable, validação da biblioteca com.apple.security.cs.disable, variáveis ​​do ambiente com.apple.security.cs.allow-dyld-environment Para o usuário, eles parecem intimidadores; portanto, se você não precisar deles, não os adicione.

Mais adiante neste artigo, assumiremos que você colocou seus direitos em um arquivo chamado entitlements.plist.

Assinatura


Este é o processo de criação de uma assinatura digital informando: quem tem acesso ao certificado de assinatura promete que esse pacote de aplicativos em particular é confiável e não é malicioso. Quaisquer alterações no pacote configurável do aplicativo (exceto para anexar uma confirmação de reconhecimento de firma, veja acima) após a assinatura invalidam a assinatura e exigem a assinatura novamente do pacote configurável.

Isso também significa que seu aplicativo não deve alterar nada no conteúdo do pacote de aplicativos, por exemplo, não coloque um cache nele.

Cada arquivo executável e biblioteca dinâmica no pacote configurável do aplicativo são assinados separadamente. Em alguns casos, as bibliotecas já podem estar assinadas. Ou seja, é mais educado e calmo assinar um pacote assinando cada elemento por vez e depois assinando o pacote inteiro. Se algum elemento já tiver uma assinatura, ele permanecerá em seu lugar.

Uma maneira grosseira, mas eficaz, é forçar a assinatura profunda, ou seja, sua assinatura será aplicada a todos os elementos do pacote de aplicativos, substituindo todas as assinaturas anteriores. É exatamente isso que faremos, porque é mais simples e porque as assinaturas anteriores podem ser inválidas ou não suficientemente fortes.

Você precisará do seguinte comando assustador:

codesign -s "Developer ID Application: <YourName>" --timestamp --options runtime -f --entitlements entitlements.plist --deep YourApp.app

A opção --timestamp significa que um carimbo de data / hora válido, necessário para reconhecimento de firma bem-sucedido, é incorporado à assinatura.

A opção --options runtime significa que a assinatura inclui "hardened runtime", que também é necessário para um reconhecimento de firma bem-sucedido.

Você pode aprender a assinatura pela equipe

codesign -d -vvvv YourApp.app

Você também deve executar o aplicativo para garantir que ele continue funcionando após a assinatura.

Se você deseja assinar elementos de uma maneira mais educada, remova os comandos -f e --deep do comando, primeiro assine todos os arquivos e bibliotecas executáveis ​​dentro do aplicativo e depois o aplicativo inteiro.

Notarização


Depois de assinar o aplicativo, é necessário fornecê-lo aos sistemas Apple para reconhecimento de firma, para dizer: "Olha, eu assinei isso."

Para fazer isso, primeiro comprima o aplicativo em um arquivo zip especial usando o comando ditto:

/usr/bin/ditto -c -k --keepParent YourApp.app YourApp.zip

Simplesmente agrupar o aplicativo em zip usando o Finder ou a linha de comando não funcionará.

Em seguida, envie um zip para notarização:

xcrun altool --notarize-app --primary-bundle-id "<id>" -u "<appleid>" -p "<app-specific password>" --file YourApp.zip

Um exemplo:

xcrun altool --notarize-app --primary-bundle-id "com.zarkonnen.airships" -u "dave@hotmail.com" -p "bwnh-pbbt-llpt-xxxx" --file Airships.zip

O ID do pacote configurável pode ser encontrado em YourApp.app/Contents/Info.plist. (Você pode abrir pacotes de aplicativos clicando com o botão direito do mouse neles e selecionando "Mostrar conteúdo do pacote".)

A notarização pode demorar um pouco. Isso geralmente leva alguns segundos ou minutos, mas às vezes pode demorar uma hora. Despeje mais chá, ou algo mais forte, escolha por si mesmo. Mais cedo ou mais tarde você terá algo parecido com isto:

No errors uploading 'YourApp.zip'.
RequestUUID = 29926ae6-f551-4d54-b283-e29d6f9b9156


Agora podemos usar o seguinte comando para verificar o status do pacote transmitido:

xcrun altool --notarization-info <RequestUUID> -u -u "<appleid>" -p "<app-specific password>"

Um exemplo:

xcrun altool --notarization-info 29926ae6-f551-4d54-b283-e29d6f9b9156 -u "dave@hotmail.com" -p "bwnh-pbbt-llpt-xxxx"

Algo semelhante será exibido:

           Data: 2019-10-08 06:59:58 +0000
           Hash: 0774fb95035408bacecebd64935a611ecd27b45ad9cbf3cc1aa48fa1e0eaa649
     LogFileURL: https: //osxapps-ssl.itunes.apple.com/itunes-assets/Enigma123 / ...
         Status: sucesso
    Código do status: 0
 Mensagem de status: Pacote aprovado 

Repito, a confirmação geralmente leva cerca de 15 minutos, mas às vezes leva várias horas para o mesmo aplicativo. Sim, assim.

Se o status for falha, consulte os erros listados pelo URL do arquivo de log. Se você obtiver sucesso, dê uma olhada de qualquer maneira, pois pode haver avisos e esses avisos podem muito bem se tornar erros quando a Apple reafirmar seus requisitos novamente.

Anexo


Por fim, "prendemos" a confirmação do reconhecimento de firma ao pacote de aplicativos, para que até um Mac possa verificá-lo sem uma conexão com a Internet. Para fazer isso, você deve executar um comando surpreendentemente curto:

xcrun stapler staple "YourApp.app"

Parabéns, você se inscreveu e autenticou o aplicativo Mac. Agora você pode distribuir o pacote de aplicativos de qualquer maneira conveniente, se ele não mudar no processo.

Java


Se você estiver no mesmo barco comigo e precisar adicionar ao pacote configurável com o aplicativo JVM, continue lendo.

Existem várias opções para combinar um pacote configurável da JVM com um aplicativo Java. Eu recomendaria o AppBundler, que é uma tarefa ant que faz todo o trabalho para você. Inicialmente, o AppBundler podia ser baixado do java.net, mas, graças à negligência da Oracle do restante da plataforma Java, agora você precisa baixar a versão mais recente em https://github.com/TheInfiniteKind/appbundler .

Lá você pode encontrar as fontes e a documentação, mas não o jar, porque se supõe que você esteja usando o Maven. Se você não estiver usando o Maven, o pote pode ser obtido aqui: https://jar-download.com/artifacts/com.panayotis/appbundler

Siga as instruções na documentação na página do github para configurar o pacote. Pessoalmente, uso o NetBeans e, para resolver o problema, inseri as seguintes linhas no build.xml:

 <nome do destino = "- pós-jar">
   <taskdef name = "bundleapp" 
     classpath = "lib / appbundler-1.1.0.jar"
     classname = "com.oracle.appbundler.AppBundlerTask" />
   <bundleapp 
       jvmrequired = "1.7"
       diretório de saída = "/ home / zar / Desktop"
       name = "Dirigíveis"
       displayname = "Dirigíveis"
       executableName = "Aeronaves"
       identifier = "com.zarkonnen.airships"
       shortversion = "1"
       version = "1"
       mainclassname = "com.zarkonnen.airships.Main"
       copyright = "2019 David Stark"
       applicationCategory = "public.app-category.games">
       <caminho da classe dir = "dist" />
       <runtime dir = "/ home / zar / Desktop / jdk-11.0.4.jdk / Conteúdo / Home" />
       <nome do arco = "x86_64" />
       <valor da opção = "- Dapple.laf.useScreenMenuBar = true" />
       <valor da opção = "- Dcom.apple.macos.use-file-dialog-packages = true" />
       <valor da opção = "- Dcom.apple.macos.useScreenMenuBar = true" />
       <valor da opção = "- Dcom.apple.mrj.application.apple.menu.about.name = Aeronaves" />
       <opção value = "- Xdock: nome = aeronaves" />
       <valor da opção = "- Dcom.apple.smallTabs = true" />
       <valor da opção = "- Dfile.encoding = UTF-8" />
       <valor da opção = "- Xmx1024M" name = "Xmx" />
   </bundleapp>
 </target> 

Esta é a tarefa executada após a criação do arquivo jar. Ele usa appbundler-1.1.0.jar para criar um pacote configurável de aplicativo com uma JVM incorporada.

O JDK usado por mim pode ser baixado em https://www.oracle.com/technetwork/java/javase/downloads/jdk11-downloads-5066655.html . Eu escolhi a versão 11 porque ela possui LTS (suporte de longo prazo), mas usa os termos de licenciamento antigos da Oracle, enquanto a versão 13 tem um novo conjunto estranho de restrições de licenciamento.

Também existem JVMs OpenJDK legalmente gratuitas, mas não consegui fazê-las funcionar com o empacotador de aplicativos.

Nota: A JVM é "Java Virtual Machine". O JRE é um "Java Runtime Environment" que inclui a JVM mais elementos adicionais, como o atualizador Java. O JDK é um "Java Development Kit" que consiste em um JRE mais as coisas necessárias para escrever programas Java, como um compilador. Antes do Java 8, o JRE estava disponível para os usuários finais separadamente, mas desde então apenas o JDK estava disponível e, portanto, associamos o ambiente de desenvolvimento Java a um jogo de computador.

Você deve poder assinar e notarizar profundamente o pacote resultante. A documentação do AppBundler possui várias opções adicionais, como adicionar um ícone, associações de tipo de arquivo e gerar uma JVM simplificada para o aplicativo.

Leitura adicional



Adição


  • O usuário do Reddit AMemoryOfEternity fez uma pergunta nos fóruns de desenvolvedores do Steam e constatou que, embora as notificações para aplicativos Steam não sejam necessárias. Eles devem ter 64 bits, mas não está claro se é obrigatório assiná-los. Link, requer acesso ao Steamworks
  • A Apple relaxou temporariamente as regras de reconhecimento de firma, portanto, por enquanto, permite reconhecer novas aplicações que não possuem tempo de execução reforçado, subcomponentes, sem ID de desenvolvedor, sem registro de data e hora, etc. Essas coisas ainda serão exibidas no relatório de reconhecimento de firma como avisos; portanto, para cuidar do futuro, é melhor tentar se livrar deles.
  • De acordo com a Valve, para que a API do Steam funcione, é necessário conceder o direito com.apple.security.cs.allow-dyld-environment-variables: “O Steam injeta a API do dylib por meio de DYLD_INSERT_LIBRARIES, que são bloqueados por padrão pelo tempo de execução protegido, mas a própria API do dylib é assinada e deve ser verificado, adicione apenas a permissão "com.apple.security.cs.allow-dyld-environment-variables" para poder atribuir variáveis ​​de ambiente DYLD ".

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


All Articles