dtls-fuzzer é uma ferramenta Java que realiza fuzzing de estado de protocolo de servidores DTLS. Mais concretamente, suporta as seguintes funcionalidades:
- dado um alfabeto, pode gerar automaticamente um modelo de uma implementação de servidor DTLS local;
- dado um teste (sequência de entradas) e um alfabeto, pode executar o teste numa implementação de servidor DTLS;
- pode executar uma tarefa de aprendizagem em lote, envolvendo múltiplas execuções de aprendizagem.
dtls-fuzzer utiliza [TLS-Attacker][tlsattacker] para gerar/analisar mensagens DTLS, bem como para manter o estado. Para esse fim, TLS-Attacker foi estendido com suporte para DTLS. dtls-fuzzer depende da [versão 3.0b][tlsattackerver] do TLS-Attacker, uma versão que implementa a melhoria DTLS.
Conteúdo do artefato
O artefato contém:
- uma descrição da estrutura de ficheiros do dtls-fuzzer, incluindo código-fonte e dados experimentais consistentes com os apresentados no artigo;
- um guia passo a passo para avaliar o dtls-fuzzer numa SUT (System Under Test)/ implementação de servidor DTLS escolhida.
Estrutura de ficheiros do dtls-fuzzer
As pastas mais importantes no diretório raiz do dtls-fuzzer são:
- 'src', diretório que contém o código-fonte Java do dtls-fuzzer;
- 'examples', diretório que contém exemplos de alfabetos, testes, especificações (ou seja, modelos) e ficheiros de argumentos que podem ser fornecidos ao dtls-fuzzer para lançar experiências de aprendizagem. Os ficheiros neste diretório são usados como entradas para experiências de aprendizagem;
- 'experiments', diretório que contém dados relativos a experiências. Alguns destes dados também servem como entrada para experiências de aprendizagem. As pastas mais notáveis são:
- 'suts', com binários para SUTs Java. Estas SUTs são programas de servidor DTLS feitos à medida cujo código-fonte está disponível publicamente;
- 'patches', patches que foram aplicados a algumas SUTs (particularmente a utilitários) antes do código-fonte ser compilado. O objetivo principal destes patches foi prevenir comportamentos induzidos por temporização durante a aprendizagem, ativar/desativar funcionalidades na SUT e configurar parâmetros como a chave pré-partilhada;
- 'keystore', material de chave (por exemplo, pares de chaves pública-privada, Java keystores) usado durante a aprendizagem;
- 'results', resultados experimentais.
Resultados experimentais
'experiments/results' contém resultados experimentais, que são o principal resultado do trabalho. Em particular
- 'all_ciphers' contém pastas de saída para todas as experiências executadas;
- 'mapper' contém resultados experimentais que ajudam a justificar algumas das decisões do mapper (ver Secção 5.2)
- 'included' contém pastas de saída para experiências convergentes (convergente significa que a aprendizagem gera com sucesso um modelo).
- note que nem todas as experiências em 'all_ciphers' foram bem-sucedidas/terminaram com um modelo final (dizemos nesses casos que a aprendizagem não convergiu)
Pastas de saída
As pastas de saída são nomeadas com base na configuração da experiência, ou seja:
- a SUT/implementação testada;
- o alfabeto usado, em termos de algoritmos de troca de chaves cobertos, onde 'all' indica que todos os 4 algoritmos de troca de chaves foram usados;
- quando aplicável, se a certificação do cliente era obrigatória (req), opcional (nreq) ou desativada (none);
- o algoritmo de teste: random walk (rwalk) ou uma adaptação do mesmo (stests);
- experiências que usam a adaptação não foram incluídas no artigo
- opcionalmente, se as retransmissões foram incluídas/excluídas das saídas (incl ou excl).
- retransmissões foram incluídas por defeito
Como exemplo, o nome da pasta 'jsse-12_rsa_cert_none_rwalk_incl' indica uma experiência na implementação JSSE 12 do DTLS, usando um alfabeto que inclui entradas para realizar handshakes RSA, a autenticação de certificado do cliente está desativada, o algoritmo de teste é random walk e as retransmissões estão incluídas.
Uma pasta de saída contém:
- 'alphabet.xml', o alfabeto de entrada;
- 'command.args', o ficheiro de argumentos usado que contém vários parâmetros da experiência, nomeadamente:
- queries, o limite no número de testes random walk que precisam de passar para uma hipótese ser considerada final
- equivalenceAlgorithms, algoritmos de teste baseados em modelo empregues
- runWait e timeout, o timeout de início e de resposta respetivamente (abordamo-los mais tarde)
- 'sul.config', configuração dependente da SUT para TLS-Attacker, a mesma configuração pode ser usada para executar traces de workflow na SUT usando apenas TLS-Attacker;
- 'hyp[0-9]+.dot', hipóteses intermédias;
- 'statistics.txt', estatísticas da experiência como o número total de testes, tempo de aprendizagem;
- A Tabela 4 apresenta estes dados
- 'nondet.log', registos de comportamento não determinístico encontrado;
- 'learnedModel.dot', no caso de a aprendizagem ter convergido, o modelo aprendido (ou seja, hipótese final);
- 'error.msg', uma mensagem de erro gerada no caso de a experiência ter falhado/a aprendizagem ter sido interrompida e, portanto, não convergir para um modelo final.
- o principal culpado é o não determinismo relacionado com tempo (as mesmas entradas levam a resultados diferentes).
O avaliador pode verificar (por exemplo) que os resultados experimentais em 'included' correspondem aos apresentados na Tabela 4, ou que as configurações testadas na Tabela 2 também aparecem em 'all_ciphers'.
Note que os modelos que aparecem no artigo foram o resultado de uma poda/trimagem significativa, enquanto que os modelos que aparecem nas pastas de saída não foram alterados.
Passos de avaliação do dtls-fuzzer
Para efeitos de avaliação do dtls-fuzzer é necessário realizar os seguintes passos:
- Garantir que os pré-requisitos são cumpridos
- Instalar o dtls-fuzzer
- Configurar a SUT
- Usar o dtls-fuzzer para gerar modelos para a SUT
- Analisar resultados
Esta secção de avaliação é seguida por um guia sobre como usar o dtls-fuzzer que introduz os seus principais casos de uso.
Garantir os pré-requisitos
dtls-fuzzer foi testado em distribuições Linux Ubuntu 18.04 e Debian 9. Deve funcionar em qualquer distribuição Linux recente. O suporte para outras plataformas não foi testado. Este guia assume que é utilizada uma distribuição baseada em Debian (que tem 'apt-get').
É necessária uma Máquina Virtual (VM) Java 8 JDK (Java Development Kit). A versão usada para executar experiências é a 1.8.0_222, embora versões posteriores do Java 8 também devam funcionar. Note que a ferramenta não compila em Java 9 ou posterior. Também dependemos do maven (o utilitário 'mvn') para gestão/implantação de dependências.
Recomendamos usar uma máquina suficientemente potente, caso contrário parâmetros de temporização sensíveis, como o tempo de espera de resposta, podem tornar-se demasiado baixos, causando saídas diferentes das obtidas no artigo. Pior ainda, podem fazer com que as experiências de aprendizagem falhem. As experiências originais foram executadas num servidor com muitos núcleos, no entanto, esperamos (embora não tenhamos testado exaustivamente) que a aprendizagem seja possível num desktop com processador i7. A aprendizagem também é possível em sistemas mais fracos se os parâmetros de temporização forem ajustados em conformidade. Finalmente, visualizar modelos .dot exportando-os para .pdf requer instalar a [biblioteca graphviz][graphviz]. Assume-se que o utilitário 'dot' fornecido pelo graphviz está localizado no PATH do sistema.
Em suma, os pré-requisitos aconselhados são:
- distribuição Linux recente, de preferência baseada em Debian
- máquina desktop/servidor para reprodução de experiências/aprendizagem fiável
- (>=) 4 GB de RAM
- Java 8 JDK
- maven
- graphviz