P31 Partition HTTP/TLS pour Pepin

De Wiki d'activités IMA


Cahier des charges

Présentation générale du projet

Contexte

L’équipe 2XS (eXtra Small, eXtra Safe) de l’IRCICA en train de développer un proto-noyau qui a une architecture plus simple (donc plus légère) qu’un noyau monolithique. Ce type d’architecture fonctionne plutôt dans l’espace utilisateur que l’espace noyau ce qui permet d’éliminer l’abstraction de matériel. Ceci permet l’interaction plus direct avec les matériels.

Description du projet

Pépin (ou PIP) est le proto-noyau développé par l’équipe dans le but de créer un système qui isole complètement les partitions de mémoire selon un modèle hiérarchique : une partition peut contenir des sous-partitions (qui peuvent elles-mêmes contenir des sous-sous-partitions). Cette isolation de mémoire garantit un niveau de sécurité élevée car les partitions de même niveau (dans la hiérarchie) ne peuvent pas communiquer entre elles.

Objectif du projet

L’intérêt de ce projet est de développer une partition qui s’exécutent au-dessus de Pépin qui héberge un serveur web et implémente un protocole d’échange sécurisé de type TLS-PSK. Pour cela, il faut adapter un serveur web existant afin de pouvoir le porter au Pépin.

Choix techniques : matériel et logiciel

Pour le développement de la partition de serveur web, on utilise le langage C et assembleur (si besoin). Pour tester le système, on l’implémente dans une carte embarquée ayant l’architecture x86 (ie : Intel Galileo).

Etapes du projet

  • Etudier l'architecture de Pépin
  • Identifier une solution existante de serveur web qui peut être adapté pour le système
  • Adapter le code du serveur web pour pouvoir utiliser avec Pépin
  • Intégrer Pépin et le serveur web dans une carte embarqué et tester la solution

Planning prévisionnel

Premier planning

Tâche Date
2016 2017
19/09 26/09 03/10 10/10 17/10 24/10 31/10 07/11 14/11 21/11 28/11 05/12 12/12 19/12 26/12 02/01 09/01 16/01 23/01 30/01 06/02 13/02 20/02
Définition de cahier des charges
Etudier l'architecture de Pépin
Identifier un serveur web existant qui peut être adapté pour le système
Compléter le code pour un serveur web embarqué et le tester dans Linux
Adapter le code du serveur web pour pouvoir utiliser avec Pépin
Intégrer et tester le serveur web dans Intel Galileo

Deuxième planning

Tâche Date
2016 2017
19/12 26/12 02/01 09/01 16/01 23/01 30/01 06/02 13/02 20/02
Adaptation de code Terminer le portage picoTCP
Ecrire une fonction PRNG et terminer le portage de wolfSSL
Intégration dans Intel Galileo Familiariser avec le driver carte réseau Galileo
Porter et tester picoTCP seul
Porter picoTCP+wolfSSL
Tester le server web dans Galileo

Avancement du Projet

Etudes de l'architecture de Pépin

Le noyau Pépin se situe au dessus de niveau matériel et se constitue d'IAL, de MAL, d'une section BOOT et une section CORE.

Arch-pepin.PNG

  • IAL: sert à la gestion de l'interruption (activer, désactiver, configurer, etc.)
  • MAL: sert à la gestion de communication avec la mémoire (MMU)
  • BOOT: contient le code pour démarrer Pépin
  • CORE: contient le code principal de noyau de Pépin
  • Multiplexeur: la couche de base de manipulation des partitions en mode utilisateur. Il fournit tous les composants systèmes non présents dans le noyau comme l'ordonnanceur


Identification d'un serveur web adapté pour Pépin

Il existe plusieurs serveur web qui ont déja été développé. La table ci-dessous résume certains serveurs web qui pourraient être porté vers Pépin

Serveur web Avantage Inconvénient SSL/TLS
Apache Plus utilisé Lourds Oui
Inadapté pour l'embarqué
LigHTTPD Léger Besoin d'un OS classique ou OS embarqué Oui
Facile à mettre en oeuvre
Mongoose Petite en taille Implémentation non complète de SSL/TLS Manque certain type de mécanisme d'échange de clé
API en C pour le dévelopement
SMEWS Très petite en taille Pas d'implementation de SSL/TLS Non
Bien adapté pour plusieurs types de systèmes embarqués

Nous avons choisi la solution Mongoose parce qu'il est bien adapté (même s'il manque certaines implémentation de SSL/TLS comme l'échange de clé par PSK). Donc, on va ajouter une couche de wolfSSL qui contient plusieurs mécanisme de TLS-PSK comme:

  • TLS_PSK_WITH_AES_128_GCM_SHA256
  • TLS_PSK_WITH_AES_256_GCM_SHA384
  • TLS_PSK_WITH_AES_256_CBC_SHA384
  • TLS_PSK_WITH_NULL_SHA384
  • TLS_DHE_PSK_WITH_AES_128_GCM_SHA256
  • TLS_DHE_PSK_WITH_AES_256_GCM_SHA384
  • TLS_DHE_PSK_WITH_AES_128_CBC_SHA256
  • TLS_DHE_PSK_WITH_AES_256_CBC_SHA384
  • TLS_DHE_PSK_WITH_NULL_SHA256
  • TLS_DHE_PSK_WITH_NULL_SHA384
  • TLS_DHE_PSK_WITH_AES_128_CCM
  • TLS_DHE_PSK_WITH_AES_256_CCM

Dans Pépin, nous devrions avoir une pile TCP/IP qui gère les couches hautes (réseau, transport et application) sachant que le driver(de carte réseau) qui s'occupe les couches bases est en cours de développement. Pour cela, on a décidé d'utiliser la solution picoTCP. Donc, la solution complète est :

Couches hautes Application Serveur web
Transport wolfSSL+ picoTCP
Réseau picoTCP
Couches bases Liaison de données
Physique
Edit: Au lieu d'utiliser le serveur web Mongoose, on implémente un serveur web simple en dessus de picoTCP+wolfSSL qui sera capable de gérer les requêtes HTTP.

Pepin HTTP.png


Compléter le code pour un serveur web embarqué et le tester dans Linux

Avant d’implementer le serveur web complet, il fallait tester d’abord le fonctionnement de picoTCP tout seul (sans glue).

picoTCP seul

Pour utiliser picoTCP sous Linux, il faut créer un tunnel TUN/TAP afin que le système d’exploitation (Linux) ne modifie pas la trame ethernet. C’est parce que l’interface de carte réseau va enlever l’entete Ethernet et va passer le payload (normalement les paquets IPs) au système. D’où l’utilisation de TUN/TAP sera utile. Un dispositif TUN/TAP peut être vu comme une interface réseau qui communique avec un programme utilisateur (dispositif logiciel) au lieu d'une vraie carte matérielle (TUN pour mimer un périphérique point à point, TAP pour mimer un périphérique Ethernet). Dans ce cas, on va utiliser une interface de type TAP.

Création de l’interface tap0 (en tant que root):

#tunctl
#ifconfig tap0 10.0.0.1

On peut tester l’impléméntation de picoTCP avec ICMP en faisant un ping vers 10.0.0.1 :

struct pico_ip4 ipaddr, netmask;
struct pico_device* dev;

dev = pico_tap_create("tap0");

//attribute ip and netmask to a new interface in tap0
pico_string_to_ipv4("10.0.0.2", &ipaddr.addr);
pico_string_to_ipv4("255.255.255.0", &netmask.addr);

pico_ipv4_link_add(dev, ipaddr, netmask);

//ping the ip address NUM_PING times
pico_icmp4_ping("10.0.0.1", NUM_PING, 1000, 10000, 64, ping_callback_function);

Ce qui donne:

Picotcp icmp.PNG

Glue picoTCP+wolfSSL+libhttps

Ensuite, il fallait implémenter la glue qui permet de faire fonctionner wolfSSL au-dessus de picoTCP et ensuite ajouter des fonctions pour traiter les paquets HTTPS. Ensuite, on utilise une fonction callback qui permet d’initialiser le serveur web avec TLS-PSK en précisant le type de chiffrage (ex : PSK-AES256-CBC-SHA). Il est aussi important de préciser la clé PSK qui sera utilisé côté client pour communiquer avec le serveur.

On peut tester la connexion et échange de données avec le serveur en utilisant l’utilitaire fourni avec openssl :

#openssl s_client -connect server_ipAddr:port -psk clé_psk

La commande openssl affiche le type de chiffrage et d'autre propriétés utilisées pour connecter au serveur web TLS-PSK.
Openssl.PNG


Capture de paquet sur Wireshark:
Wireshark pcap.PNG

Adaptation de code de serveur web pour Pépin

Dans cette partie, il y a deux travaux principaux à faire. D’une part, il faut interfacer la solution picoTCP avec le driver de la carte réseau et d’autre part porter des bibliothèques spécifiques à Linux (utilisées dans cette solution) pour pouvoir adapter avec Pépin.

Portage de fonction spécifique Linux vers Pépin

Fonction(s) à porter Commentaires Avancement
picoTCP Allocations mémoire Les fonctions comme malloc et calloc (allouer espace mémoire et l’initialiser à zéro) doivent être adaptées en fonction de l’architecture de mémoire du système. Il faut aussi porter la fonction free pour libérer l’espace mémoire allouée. Terminé
Date On doit écrire une fonction pour retourner la date (en s ou ms). Celle-ci est utile pour faire un délai comme la fonction sleep. (Edit: il existe une fonction pip_time dans Pépin qui retourne le nombre de tick écoulé depuis le démarrage de système. On peut utiliser cette fonction pour faire le délai.) Terminé
wolfSSL Les fonctions de la bibliothèque math surtout pow et log Ces fonctions sont définies dans la bibliothèque math de Linux mais il faut réécrire pour Pépin. Elles sont utilisés dans l’algorithme de Diffie-Hellman. Terminé
RNG/PRNG wolfSSL utilise /dev/random ou /dev/urandom pour génerer des nombres aléatoire. Puisque cette ressource n’est pas disponible dans Pépin, on va écrire une fonction générateur RNG ou PRNG Terminé

Interfacage picoTCP avec le driver Ethernet

Afin que la pile TCP/IP fourni par picoTCP fonctionne bien dans Galileo, il faut interfacer pioTCP avec le driver de la carte réseau Galileo. Les fonctions que contient le driver sont:

  • eth_init: Cette fonction est utilisée pour initialiser totues les variables et les registres concernant la carte réseau
  • get_MAC_Addr: Cette fonctionne récupère l'adresse MAC de la carte NIC
  • poll: Sert à récupérer les trames (en mode scrutation) qui arrivent sur l'interface réseau de Galileo (cette méthode est appelée de façon répétée)
  • send: Sert à envoyer la trame Ethernet vers le réseau

Intégration de la solution dans la carte Intel Galileo

Amorçage (boot) de système

On utilise l'hierarchie ci-dessous pour démarrer le noyau de Pépin dans Galileo:
Boot dir tree.png

Dans grub.conf, on a:

default 0
timeout 5

title Multiboot GRUB
  root (hd0,0)
  chainloader /efi/boot/grub.efi

Et dans grub.cfg, on a:

set default=0
set timeout=5

menuentry 'Pepin' {
  set root='hd0,msdos1'
  multiboot /kernel/pepin.bin ro
}

Maintenant, on peut booter Pépin dans Galileo. Donc, je peux commencer à tester le serveur web dans Galileo.

Tester la solution

Quand je fais le test en démarrant Galileo avec Pépin, je me suis rendu compte que l'envoi et la réception de trame ne fonctionne pas comme prévue. Du coup, j'ai décidé d'utiliser le protocole SLIP qui envoi les trames sur la liaison série.

Liaison SLIP.png

Ce protocole ajoute ou modifie certains octet dans la trame comme ci-dessous:

Valeur hexadécimale Abbréviation Description
0xC0 END Fin de la trame
0xDB ESC Caractère d'échappement
0xDC ESC_END Transposition du caractère Fin de trame
0xDD ESC_ESC Transposition du caractère d'échappement

Afin qu'un PC puisse récupérer les trames du protocole SLIP sur la liaison série, on associe une interface réseau à une liaison série avec la commande slattach puis ajouter l'adresse IP à cette interface.

#!/bin/sh

slattach -L -s 115200 -p slip /dev/ttyUSB0 -d &
sleep 1
ifconfig sl0 10.0.0.1 dstaddr 10.0.0.2 mtu 1500 

echo 1 > /proc/sys/net/ipv4/ip_forward
echo 1 > /proc/sys/net/ipv4/conf/all/proxy_arp

socat tcp-l:443,reuseaddr,fork file:/dev/ttyUSB0,nonblock,raw,echo=0,waitlock=/var/run/tty &

Pour que le protocole de SLIP marche bien, j'ai désactivé tout type de debug qui envoi les caractères/chaîne de caractères sur la liaison série. Ensuite, j'ai utilisé l'outil wireshark pour écouter les trames qui transitent.

Wireshark capture.PNG

Mais, il semble que le test ping ne marche pas dû au fait que la réception de paquet avec la protocole SLIP pose des problèmes. En effet, je suis en train de débugger pour trouver une solution à ce bogue.

Code sources

Tous les codes sources se trouvent dans GitHub. Les répertoires concernant ce projet:

  • libpip
  • pipcore
  • picotcp
  • wolfssl
  • picowebstack
  • picoTCP_test

Et, il faut aussi le code source de openlibm

Références

Introduction à l'exo-noyau
A propos de SMEWS
Introduction de picoTCP
Article à propos de Mongoose dans Linux Journal
Documentation wolfSSL
Site de Pépin (ou Pip en anglais)