Accueil
Rechercher:
sur developpez.com sur les forums
Forums | Tutoriels | F.A.Q's | Participez | Hébergement | Contacts
Club Emploi Blogs   TV   Dév. Web PHP XML Python Autres 2D-3D-Jeux Sécurité Windows Linux PC Mac
Accueil Conception Java DotNET Visual Basic  C  C++ Delphi MS-Office SQL & SGBD Oracle  4D  Business Intelligence
FORUMS .NET FAQs .NET TUTORIELS .NET SOURCES .NET LIVRES .NET OUTILS .NET BLOG .NET DOTNET TV

Signature d'assembly avec .Net

Date de publication : 17/08/2006

Par Ronald VASSEUR (autres articles)

MVP Visual Developer - Visual Basic
 

Un élément de base de la sécurité des applications .Net repose sur la signature d'assemblies et l'utilisation de noms forts. L'environnement de développement .Net de base (le SDK) nous propose des utilitaires permettant d'effectuer ces opérations. Même si la signature d'assembly n'est pas un élément de sécurité suffisant, il consitue néamoins la pierre angulaire de la sécurité d'exécution de code .Net. Au cours ce cet article nous verrons à quoi correspondent tous ces procédés de signatures, mais aussi comment les appliqués, quelles sont leurs limites, et ce que l'on peut en attendre concrètement.

Introduction
Clé publique et clé privée ?
Qu'est-ce qu'une signature ?
1. Qu'est-ce que la signature d'assembly ?
1.1. Strong Names ou Nom Fort
1.2. Hashage de l'assembly
2. Signer son assembly avec sn.exe
2.1. Application exemple
2.2. Signature de l'assembly
2.3. La signature plus en détails
3. Intégration dans Visual Studio 2005
4. Présentation de sn.exe
5. Signature d'assembly dans un processus de développement
5.1. Les inconvénients et contraintes de la signature
5.2. Le delay signing
5.2.1. Présentation
5.2.2. Extraction de la clé publique
5.2.3. Signature partielle
5.2.4. Désactivation de la vérification
5.2.5. Signature définitive de l'assembly
5.3. Le test key signing
5.3.1. Présentation
5.3.2. Démonstration
Ressources
Conclusion


Introduction


Clé publique et clé privée ?

On parle de clé publique et de clé privée pour les algorithmes de chiffrement asymétrique. Ces clés permettent de crypter et de décrypter un message, elles seules permettent cette action. La clé publique ne doit pas être gardée secrète et peut être diffusée sans que la confidentialité du message ne soit affectée, par contre, la clé privée, comme son nom l'indique doit rester privée, sa divulgation rendrait inefficace le cryptage, car elle permet de décrypter le message. Pour résumer la clé publique sert à coder un message, alors que la clé privée sert à le décoder. Mais attention, le terme publique et privée sont subjectif, en effet, chacune des clés peu remplir ce rôle, c'est juste que l'on attribue un rôle à chacune, rôle qui bien évidemment n'est plus interchangeable par la suite. La longueur des clés est exprimée en bits, elle va généralement de 128 à 1024 bits suivant le type de clé et d'algorithme. Seuls les algorithmes asymétriques utilisent un jeu de deux clés, les algorithmes symétriques eux, n'utilisent qu'une seule clé.
Dans le contexte de la signature d'une assembly, on la signe au préalable avec la clé privée uniquement. La clé publique quant à elle nous servira à contrôler la validité de cette signature.


Qu'est-ce qu'une signature ?

Une signature électronique permet principalement de garantir que le contenu d'un document n'a pas été modifié après qu'il ait été signé. Appliqué aux assembly .Net elle garanti l'intégrité du contenu d'origine. Le procédé de signature d'assembly prend donc tout son sens en termes de sécurité et de garantie d'authenticité d'un programme.


1. Qu'est-ce que la signature d'assembly ?

La signature d'une assembly .Net comporte deux composantes fondamentales : hashage de son contenu et un nom fort. Voyons sans plus tarder à quoi correspondent ces deux concepts.


1.1. Strong Names ou Nom Fort

Un nom fort, ou "Strong Names" en anglais (d'ailleurs au cours de cet article nous utiliserons la version française et anglaise sans distinction) correspond à un ensemble d'éléments qui permettent d'identifier avec certitude une assembly donnée. Un nom fort est donc composé des éléments suivants :

  • Une version
  • Un nom simple
  • Une clé publique
  • Une clé privée
  • Ainsi qu'une culture et une architecture CPU (x86 / x64) optionnelles
Une version est simplement une séquence de quatre chiffres agencés de la sorte :
Numéro majeur de version - Numéro mineur de version - Numéro de "build" - Numéro de révision, cela peut être par exemple "2.7.3.6".

Un nom simple, il s'agît du nom que le développeur à donné à l'assembly, généralement c'est le nom du fichier sans son extension (.dll, .exe,...), il faut donc bien faire attention à ne pas mélanger cela avec un Namespace ou à un nom de classe.

Une clé publique, qui va permettre à l'environnement .Net de vérifier la signature de l'assembly signée avec une clé privée. En effet, une et une seule clé publique correspond à une clé privée. La clé publique sert donc de référent. La clé publique peut être communiquée sans risque. Cette clé publique est toujours intégrée à une assembly signée, et est assez facile à récupérer au sein d'une assembly pour tout développeur .Net aguerri.

Une clé privée, cette clé est celle qui a servie à signer l'assembly, sa valeur doit rester secrète, en effet elle seule garantie l'authenticité et la non corruption du contenu d'une assembly. Sa gestion est donc sensible, mais nous y reviendrons plus tard.

.Net


Une culture, pour simplifier il s'agît de la langue et des réglages régionaux, cela peut être US, FR ou autre...

Une architecture de processeur, information en relation avec la machine de destination prévue pour l'assembly, à ce jour Intel (par exemple x86, x64 ou même Itanium)."

Un nom fort est donc un ensemble de procédés et de valeurs qui garantissent l'authenticité et la non corruption d'une assembly. Un nom fort est donc un composant de la technologie .Net qui peut s'avérer extrêmement intéressant dans la gestion de la sécurité. De plus, la signature d'assembly est indispensable pour la gestion du versionning d'assembly ou encore pour placer une assembly dans le GAC (Global Assembly Cache).


1.2. Hashage de l'assembly

En l'état, ce que nous savons de la signature d'une assembly est le fait que l'on utilise un certains nombres de paramètres pour identifier de manière unique une assembly, notamment par le biais d'une clé publique, ou plutôt d'un jeton correspondant à cette clé publique qui est intégré directement dans l'assembly. Cependant, il manque un élément important de la signature, en effet jusqu'ici rien ne prouve qu'une assembly signée n'ait pas été modifiée depuis qu'elle a été compilée par le développeur. Pour ce faire, un autre procédé va entrer en jeu, il s'agit du hashage. Voyons cela plus en détails.

Tout d'abord le hashage est un procédé mathématique reposant sur des algorithmes permettant de créer une sorte de condensé unique d'un texte ou du moins d'en ensemble de caractères, condensé à partir duquel, il sera absolument impossible de retrouver le texte original, c'est le propre du hashage d'être unidirectionnel et définitif. Pour résumer, après hachage d'une chaîne de caractères on obtient un condensé unique et définitif appelé hash, permettant d'identifier de manière unique et certaine un texte, qui dans notre cas sera le code IL (Intermediate Language) d'une assembly ainsi que certains paramètres de son manifest.

Ce hash est calculé lors de la compilation de notre code (VB.Net, C# ou autre...) en IL, bien évidemment ce hash n'est calculé que si l'on à indiqué au compilateur que l'on souhaitait signer notre assembly. Après calcul de ce hash, celui-ci est encrypté à l'aide de la clé privée, et inscrit dans notre assembly. Dès lors je pense que vous pouvez dors et déjà entrevoir la suite... La clé publique qui à été inscrite dans le manifeste de notre assembly, c'est-à-dire dans les métadonnées, va servir à décoder le hash qui y est stocké, et sera comparé avec le résultat du hachage obtenu par l'environnement d'exécution de .Net lors du chargement de l'assembly. Si le hash décrypté par la clé publique contenu dans l'assembly est semblable au hash calculé par l'environnement d'exécution alors l'assembly peut être chargée, dans le cas contraire une exception est levée, et le chargement annulé.

Ainsi grâce à ce procédé de hashage l'on peut déterminer avec certitude si l'assembly à été modifiée ou non depuis qu'elle à été signée par le développeur. Cette certitude repose bien entendu sur la non divulgation de la clé privée qui a servie au cryptage du hash obtenu au moment de la signature.

Au cours de cette partie nous avons pu voir que la signature d'une assembly repose sur un Strong Name qui est un ensemble d'éléments, ainsi que sur le calcul d'un hash de son contenu. La conjugaison des deux va permettre d'identifier avec certitude et de manière unique une assembly, et de garantir que celle-ci n'a pas été modifiée depuis qu'elle a été signée par le développeur à l'aide d'un couple clé publique/clé privée. Même si ce procédé semble est très utile et performant il possède, comme nous le verrons un peu plus tard, certaines limites et contraintes, il participera sans aucun doute au processus de sécurisation du code d'une application, mais il ne peut pas prétendre à incarner la sécurité à lui tout seul.


2. Signer son assembly avec sn.exe

Le SDK du Framework .Net intègre un petit outil en ligne de commande indispensable, il permet de générer le couple clé publique/clé privée RSA permettant de signer votre assembly. Cet outil est très pratique et vous l'utiliserez fréquemment, pour cela nous l'étudierons en détails plus loin dans cet article, ici je me bornerai à vous donner les commandes nécessaires à notre objectif.


2.1. Application exemple

Nous allons utiliser une application console pour toutes les démonstrations de cet article, donc ce sera une application réduite à sa plus simple expression. Il ne vous reste qu'à ouvrir Notepad ou votre éditeur de texte préféré, et copier le code ci-dessous et enregistrer le fichier sous StrongNamesApplication.vb.
Application exemple
Imports System
Imports System.Reflection

<Assembly: AssemblyKeyFile("c:\maCle.snk")>

Module StrongNamesApplication

    Sub Main()
        Console.WriteLine("Application de test de la signature d'assembly avec des noms forts.")
    End Sub

End Module
Comme vous le voyez ci-dessus, l'application console se contente d'afficher un texte lors de son exécution.


2.2. Signature de l'assembly

Lancer donc l'invite de commande de Visual Studio (ou du SDK du Framework .Net), dès lors depuis cette console vous avez accès en ligne de commande à l'outil sn.exe (sn, pour "Strong Names"). Voici la ligne de commande à saisir pour générer la paire de clés RSA :

Généartion d'une paire de clés avec sn.exe
Un fichier *.snk est crée, ce fichier contient deux clés : une publique et une privée, vous devais prendre garde à ce que ce fichier ne soit pas divulguée, tout du moins la clé privée qu'il contient. Cette clé privée permet de signer l'assembly.

Une fois cette étape passée, il faut maintenant signer notre assembly, cela se fait par le biais du compilateur de votre langage préféré (vbc.exe pour VB.Net, et csc.exe pour C#). Voyons sans plus tarder comment procéder en ligne de commande (la signature d'assembly depuis Visual Studio 2005 sera plus dans la partie suivante de cet article).

Compilation de notre application console
Une fois cette commande terminée, une exécutable (StrongNamesApplication.exe) est crée, il s'agit de notre assembly, de notre application. Vous pouvez la lancer en tapant dans l'invite de commande StrongNameApplication.exe, vous voyez alors s'afficher le texte qui doit être affiché par notre application console exemple.

Tout ceci est bien sympathique, mais un peu fastidieux, surtout si vous devez jongler avec plusieurs assembly que vous les recompilez fréquemment. De plus pourquoi se compliquer la vie si vous possédez un logiciel tel Visual Studio 2005 qui automatise ces tâches. Voici comment procéder pour signer vos assembly depuis Visual Studio 2005.


2.3. La signature plus en détails

Nous allons utiliser l'outil ILDASM fournit avec le SDK du Framework .Net, il permet de parcourir les assembly pour afficher le code qu'elles contiennent ainsi que les métadonnées, il permet également de désassembler des assembly .Net, et d'afficher le code IL de cette dernière. Ensuite nous utiliserons l'outil ILASM qui lui permet d'assembler du code IL pour générer un *.exe ou une *.dll.

Vous allez me dire quel intérêt pour notre article d'aller voir au coeur de l'assembly ? Tout simplement voir l'incidence directe de la signature, et aussi pour mettre à l'épreuve le processus de vérification de signature des assembly lors de leur chargement par l'environnement d'exécution.

Première étape, le désassemblage de notre dll, nous allons produire un fichier texte contenant le code MSIL.

Dans l'invite de commande de Visual Studio 2005, tapez ildasm puis [entrée]. La fenêtre du programme s'ouvre, cliquez alors sur le menu "Fichier", puis "Ouvrir", sélectionnez alors l'assembly.

L'assembly est maintenant chargée dans ildasm, l'on peut parcourir le manifest et ses métadonnées, mais aussi tout le code MSIL.

Désassembleur du SDK : IL DASM
Désassembleur du SDK : IL DASM


Maintenant, cliquez sur le menu "Fichier", puis "Dump", cochez toutes les options disponibles, laissez utf-8 comme format, et cliquez sur "Ok". Enregistrez le fichier, il aura une extension *.il, pour "Intermediate language". Un fichier du même nom sera aussi créée, mais il aura lui l'extension *.res, c'est un fichier de ressources qui contient des informations relatives à l'assembly que vous avez "dumpé".

Options du dump réalisé avec IL DASM
Options du dump réalisé avec IL DASM


Dans Visual Studio, ouvrez le fichier avec l'extension *.il qui à été crée par ildasm, il contient les métadonnées et tout le code MSIL de votre assembly.

Tout d'abord si vous avez correctement signé votre assembly et sélectionné toutes les options nécessaires lors du dump, vers la ligne 905/ 910 vous devez trouver la clé publique à qui à été copiée :
Clé publique
  .publickey = (00 24 00 00 04 80 00 00 94 00 00 00 06 02 00 00   // .$..............
                00 24 00 00 52 53 41 31 00 04 00 00 01 00 01 00   // .$..RSA1........
                0B 59 D3 4B 42 CB F4 69 3C AB D0 60 AE 6D C7 0D   // .Y.KB..i<..`.m..
                1B 62 4E 78 A6 30 21 E4 E3 32 6B 3F 25 52 62 E8   // .bNx.0!..2k?%Rb.
                66 D0 F2 E0 19 34 91 9E 47 4B 71 35 A5 2A 24 44   // f....4..GKq5.*$D
                06 56 B2 FD C5 D9 1E 8B EF 12 0D 00 7D 5C 01 E0   // .V..........}\..
                58 44 A2 92 D5 5F BE 6E 99 80 D0 22 12 5B AD 30   // XD..._.n...".[.0
                CE 1F 78 61 A8 8D 8B 36 EE DC A0 A6 1F 26 80 0D   // ..xa...6.....&..
                F0 63 9C B1 71 54 99 42 C0 6B 3C 86 47 B7 BA 3F   // .c..qT.B.k<.G..?
                7D 08 5F E5 A5 EE A6 09 CD 63 AA 17 AA 27 04 BD ) // }._......c...'..
(Bien évidemment comme vous avez une clé différente, ce ne sera pas les mêmes valeurs que celles-ci-dessus).

Cette clé, comme je vous l'ai indiqué plus haut, va servir à vérifier la signature de l'assembly et à la valider lors de son chargement par l'environnement d'exécution .Net. En l'état, notre assembly signée doit passer l'étape de la validation avec succès, en effet elle n'a pas été altérée. Cependant pour bien voir que la signature d'assembly n'est pas un gadget, nous allons altérer notre assembly, puis la réassembler, et enfin tenter d'exécuter notre application console pour voir ce qu'il se passe.

Altération de notre assembly :

Sur la ligne après la clé publique, vous devez avoir la ligne suivante
Version de l'assembly
  .ver 1:0:0:0
Remplacez 1:0:0:0 par les chiffres que vous voulez (par exemple 2:1:3:7), ils correspondent au numéro de version de l'assembly. Une fois cette modification effectuée, enregistrez le fichier, et fermez-le.

Dans l'invite de commande de Visual Studio 2005 (ou du SDK), tapez ce qui suit :
Assembler le code MSIL
ilasm /EXE c:\StrongNamesApplication.il
L'assemblage de notre fichier contenant le code MSIL commence, et doit se terminer par :
Fin de l'assemblage
Operation completed successfully
Un fichier StrongNamesApplication.exe est alors crée, tentez de le lancer depuis la console. Une exception doit alors être levée, car nous avons altéré l'assembly, et le résultat du hash ne correspond plus à celui effectué lors de la signature de l'assembly par le développeur. Voici ce que vous devez voir apparaître :

Erreur de lors de la validation de la signature

Puis dans la console, l'exception suivante est levée :
La validation de l'assembly à échouée
Exception non gérée : System.IO.FileLoadException: Impossible de charger le fichier ou l'assembly 
'StrongNamesApplication, Version=1.0.0.0, Culture=neutral, PublicKeyToken=5ce9c151c1a0a833' 
ou une de ses dépendances. Échec de la validation de nom fort. (Exception de HRESULT : 0x8013141A)
Nom du fichier : 'StrongNamesApplication, Version=1.0.0.0, Culture=neutral, 
PublicKeyToken=5ce9c151c1a0a833' ---> System.Security.
SecurityException: Échec de la validation de nom fort. (Exception de HRESULT : 0x8013141A)
La zone de l'assembly qui a échoué était :
MyComputer
Nous voyons donc que lors de la vérification de la signature l'environnement .Net à détecté grâce au hashage que le contenu de l'assembly à été modifié, il à donc refusé de lancer notre application et a levé une exception.


3. Intégration dans Visual Studio 2005

Signer une assembly avec Visual Studio est extrêmement simple, voici la démarche à suivre :

En premier il faut générer une paire de clés avec l'utilitaire sn.exe (voir la commande un peu plus haut dans cet article), puis ensuite, il faut faire un clic droit -> propriété dans l'explorateur de solution comme le montre l'image ci-dessous :

Explorateur de solution


Ensuite aller dans l'onglet signature, cocher la case "Signer l'assembly", puis sélectionner le menu "Parcourir" et pointer vers le fichier *.snk que vous avez généré précédemment.

Signer l'assembly


Votre assembly est dès lors prête pour la signature, cela va être effectué par le compilateur. Pour cela cliquez dans le menu "Générer en haut dans Visual Studio 2005, comme ci-dessous :

Signature de l'assembly lors de la compilation


Votre assembly est désormais signée, la compilation a réussie, la fenêtre "Sortie" le confirme :

L'assembly est signée !
Voilà, pas la peine d'en rajouter, c'est aussi simple que cela.


4. Présentation de sn.exe

SN.exe est un utilitaire qui permet de signer les assemblies .Net avec des noms fort. Cet outil en ligne de commande permet également la gestion des clés RSA utilisées pour la signature, ainsi que toutes les opérations apparentées comme par la désactivation de la vérification de signature.

Voici un tableau issu de la documentation Microsoft MSDN relatif aux commandes et paramètres de sn.exe qui est fournit dans le SDK du Framework .Net 2.0.

Option Description
-c [csp] Définit le fournisseur de services de chiffrement à utiliser pour la signature de noms forts. Ce paramètre s'applique à l'ensemble de l'ordinateur. Si vous ne spécifiez pas de nom de fournisseur de services de chiffrement, Sn.exe annule le paramètre en cours.
-d container Supprime le conteneur de clé spécifié du fournisseur de services de chiffrement de noms forts.
-D assembly1 assembly2 Vérifie que deux assemblys ne se distinguent que par leur signature. Cette vérification intervient souvent après la nouvelle signature d'un assembly avec une paire de clés différente.
-e assembly outfile Extrait la clé publique d'assembly et la stocke dans outfile.
-h Affiche la syntaxe et les options de commande de l'outil.
-i infile container Installe la paire de clés d'infile dans le conteneur de clé spécifié. Le conteneur de clé réside dans le fournisseur de services de chiffrement de noms forts.
-k [taille_de_clé] fichier_sortie Génère une nouvelle clé RSACryptoServiceProvider de la taille spécifiée et l'écrit dans le fichier spécifié. Une clé publique et une clé privée sont écrites dans le fichier. Si vous ne spécifiez pas de taille de clé, une clé de 1 024 bits est générée par défaut si le fournisseur de services de chiffrement avancé Microsoft est installé ; sinon, une clé de 512 bits est générée. Le paramètre taille_de_clé prend en charge des longueurs de clé allant de 384 bits à 16 384 bits dans des incréments de 8 bits si le fournisseur de services de chiffrement avancé Microsoft est installé. Il prend en charge des longueurs de clé allant de 384 bits à 512 bits dans des incréments de 8 bits si le fournisseur de services de chiffrement de base Microsoft est installé.
-m [y|n] Spécifie si les conteneurs de clés sont propres à l'ordinateur ou propres à l'utilisateur. Si vous spécifiez y, les conteneurs de clés sont propres à l'ordinateur. Si vous spécifiez n, les conteneurs de clés sont propres à l'utilisateur. Si ni y ni n sont spécifiés, cette option affiche le paramètre en cours.
-o infile [outfile] Extrait la clé publique d'infile et la stocke dans un fichier .csv. Chaque octet de la clé publique est séparé par une virgule. Ce format s'avère utile pour les références de codage en dur aux clés sous forme de tableaux initialisés dans le code source. Si vous ne spécifiez pas d'outfile, cette option place la sortie dans le Presse-papiers.
-p infile outfile Extrait la clé publique de la paire de clés figurant dans infile et la stocke dans outfile. Cette clé publique permet de temporiser la signature d'un assembly à l'aide des options /delaysign+ et /keyfile de Assembly Linker (Al.exe). En cas de temporisation de la signature d'un assembly, seule la clé publique est définie au moment de la compilation et un espace est réservé dans le fichier pour la signature qui sera ajoutée par la suite, lorsque la clé privée sera connue.
-pc container outfile Extrait la clé publique de la paire de clés figurant dans container et la stocke dans outfile.
-q[uiet] Spécifie le mode silencieux ; supprime l'affichage des messages de réussite.
-R[a] assembly fichier_entrée Signe à nouveau un assembly ayant préalablement fait l'objet d'une signature ou dont la signature a été temporisée avec la paire de clés figurant dans infile. Si vous utilisez -Ra, les hachages sont recalculés pour tous les fichiers dans l'assembly.
-Rc[a] conteneur_assembly Signe à nouveau un assembly ayant préalablement fait l'objet d'une signature ou dont la signature a été temporisée avec la paire de clés figurant dans container. Si vous utilisez -Rca, les hachages sont recalculés pour tous les fichiers dans l'assembly.
-Rh assembly Recalcule des hachages pour tous les fichiers de l'assembly.
-t[p] infile Affiche le jeton de la clé publique stockée dans infile. Le contenu de infile doit être une clé publique générée précédemment à partir d'un fichier de paires de clés à l'aide de -p. N'utilisez pas l'option -t[p] pour extraire directement le jeton d'un fichier de paires de clés.
-T[p] assembly Affiche le jeton de la clé publique de l'assembly. L'assembly doit correspondre au nom d'un fichier qui contient un manifeste d'assembly.
-v assembly Vérifie le nom fort figurant dans assembly, où assembly correspond au nom d'un fichier comportant un manifeste d'assembly.
-vf assembly Vérifie le nom fort figurant dans assembly. À la différence de l'option -v, -vf force la vérification même si celle-ci a été désactivée à l'aide de l'option -Vr.
-Vl Répertorie les paramètres en cours pour la vérification des noms forts sur cet ordinateur.
-Vr assembly [userlist] [infile] Inscrit assembly pour que la vérification soit ignorée. Vous pouvez également spécifier une liste de noms d'utilisateur avec la virgule comme séparateur. Si vous spécifiez infile, la vérification reste activée, mais la clé publique figurant dans infile est utilisée au cours des opérations de vérification. Assembly peut être spécifié sous la forme *, strongname pour inscrire toutes les assemblies avec le nom fort spécifié. Strongname doit être spécifié en tant que chaîne de chiffres hexadécimaux représentant la clé publique sous forme de jetons. Consultez les options -t et -T pour afficher le jeton de la clé publique.
-Vu assembly Annule l'inscription d'assembly pour que la vérification soit ignorée. Les mêmes règles d'affectation de noms aux assemblies s'appliquent aux options -Vr et -Vu.
-Vx Supprime toutes les entrées des vérifications ignorées.
-? Affiche la syntaxe et les options de commande de l'outil.
Je n'entrerai pas plus dans le détail, en effet, au cours de l'article nous abordons les scénarios d'utilisation les plus fréquent.


5. Signature d'assembly dans un processus de développement

Jusqu'ici nous avons abordé la signature d'assembly avec des noms forts d'un point de vue relativement théorique. Ici nous allons nous placer dans une optique plus concrète, en voyant comment il est possible d'intégrer cette sécurité au sein d'un processus de développement. Cela va consister principalement à voir quels sont les inconvénients de la signature, ainsi de quelle manière il est possible de gérer au mieux la sécurité de la clé privée, qui est la clé de voute de la signature.


5.1. Les inconvénients et contraintes de la signature

Tout procédé qui présente des avantages, présente également des inconvénients, la signature d'assembly n'échappe pas à la règle. D'ailleurs dans notre cas précis il est plus judicieux de parler de contrainte que d'inconvénients. En effet, vous allez voir que signer ses assemblies peut se révéler assez lourd si l'on ne s'y prend pas correctement, surtout en cas de gros développements.

La contrainte majeure de la signature d'assembly est paradoxalement la sécurité. Cela s'explique très facilement lorsque l'on comprend que la fiabilité de cette signature repose sur le secret de la clé privée, tout repose sur cette clé. Si la clé privée est dévoilée, alors le secret, est donc la signature tombe, ce n'est ni plus ni moins qu'un élément relatif à la cryptographie employant de algorithmes asymétriques. Nous voyons donc que la contrainte majeure est le fait que la sécurité du processus de génération et du stockage de la clé privée doit être totale.

Une autre contrainte découlant de la première est qu'il va falloir utiliser en cas de gros développement notamment des astuces quand à la signature d'assembly en cours de développement, nous le verrons en particulier avec le "Delay Signing" et le "Test Key Signing" qui sont deux procédés permettant de n'avoir à signer définitivement nos assemblies qu'une fois le développement terminé, sans pour autant devoir être privé des avantages et des impératifs procurés par la signature au cours du processus de développement (notamment en cas d'utilisation du versionning dans le GAC et du besoin d'avoir des noms forts pour les assemblies).

Et enfin, un réel inconvénient, lui lié au "Delay Signing" que nous allons voir juste après est le fait de devoir désactivé la vérification réalisée par le CLR lors du chargement de l'assembly, en effet cela peut être une brèche relativement importante dans la sécurité du poste de développement, partant bien évidemment du principe qu'une telle opération ne devra jamais être réalisée en environnement de production. Heureusement, nous allons voir que .Net 2.0 nous apporte quelques évolutions bien précieuses dans ce domaine.


5.2. Le delay signing

Une solution permettant de protéger beaucoup plus efficacement la clé privée, est le "Delay Signing", ou la signature différée, voyons la plus en détails sans plus tarder.


5.2.1. Présentation

Comme nous l'avons vu précédemment, l'utilisation de la clé privée par un grand nombre de personnes sur de multiples machines est un risque au plan de la sécurité. Pour palier à ce problème, il existe une solution pour contourner cela et ne pas être obligé de faire circuler la clé privé : c'est le "delay signing", on pourrait traduire cela par "signature différée". Cela consiste à utiliser uniquement le jeton de la clé publique pour l'intégrer dans l'assembly, ainsi elle possède un nom fort (ce qui est nécessaire dans nombre de situations de développement), mais par contre elle ne peut pas passer la validation de l'environnement d'exécution, il faut donc désactiver cette vérification jusqu'à ce que la signature avec la clé privée soit effectivement réalisée, signature qui interviendra généralement juste avant la livraison du produit, et sera effectuée par un nombre restreint de personnes pour des raisons évidentes de sécurité.

Voici la démarche à suivre pour utiliser le "delay signing"


5.2.2. Extraction de la clé publique

Tout d'abord, il faut extraire la clé publique du fichier snk, en effet nous voulons ne diffuser que cette dernière, et ainsi garder la clé privée secrète. Pour cela nous allons utiliser l'utilitaire sn.exe :

Extraction de la clé publique

5.2.3. Signature partielle

Maintenant que nous avons extrait notre clé publique, nous allons compiler notre application en la signant partiellement. Pour cela, deux possibilités :

En ligne de commande :
Delay Signing
vbc /delaysign+ /keyfile:c:\maClePublique.pk StrongNamesApplication.vb
Avec Visual Studio 2005 :

Pour signer partiellement l'assembly, c'est très simple, il faut aller dans les propriétés de votre projet (clic droit sur le projet dans l'explorateur de solution, puis "propriétés", onglet " signature "), cocher "signer l'assembly", puis sélectionner votre clé publique (fichier *.pk) dans la liste déroulante, et cocher "Différer la signature". Lors de la prochaine génération de votre projet, l'assembly de signée partiellement.

Delay Signing avec Visual Studio 2005


En l'état, si vous essayer de charger votre assembly, l'environnement d'exécution lèvera une exception, car vous n'avez pas utilisé la clé privée pour la signature et le hash n'a pas été effectué. Il faut donc désactiver la vérification lors du chargement.


5.2.4. Désactivation de la vérification

Ici deux possibilités, toutes deux accessibles par l'utilitaire en ligne de commande sn.exe

  • Soit on indique explicitement l'assembly pour laquelle on désactive la vérification. Pour cela, voici la commande :
Désactiver la vérification pour une assembly
  • Soit on désactive la vérification pour le jeton correspondant à la clé publique, ainsi toutes les assemblies partiellement signées grâce à une clé publique donnée pourront être chargées sans problème. Pour cela, voici la commande :
Désactiver la vérification pour un jeton
idea Remarque : vous pouvez facilement récupérer la valeur du jeton de la clé publique d'une assembly, pour cela il suffit d'utiliser la commande "sn -T [assembly]".
Récupération de la valeur du jeton
Récupération de la valeur du jeton


Une fois le développement terminé, il est bien évidemment possible de réactiver la vérification pour l'assembly concernée, ou pour le jeton de la clé publique en question. Pour cela, il faut utiliser la commande suivante :

Réactiver la vérification pour une assembly
Réactiver la vérification pour une assembly


Réactiver la vérification pour un jeton
Réactiver la vérification pour un jeton


Vous pouvez également connaître la liste des assembly et/ou des jetons pour lesquels la vérification est désactivée, pour cela il faut utiliser la commande suivante :
Assembly pour lesquelles la vérification est désactivée
sn -Vl
Vérifications désactivées

5.2.5. Signature définitive de l'assembly

Il n'est pas nécessaire de régénérer votre application, donc vous n'avez pas à passer par la case compilateur ! C'est quand même bien pratique. Voici la commande à utiliser en ligne de commande :
Signature définitive de l'assembly
sn -R StrongNamesApplication.exe c:\maCle.snk
Signature définitive de l'assembly
Signature définitive de l'assembly


idea Remarque : l'ajout de "a" après le "R" permet de recalculer le hash pour l'assembly.
Il ne nous reste plus qu'à vérifier que la signature définitive avec la clé publique à correctement fonctionné, pour cela nous allons utiliser le commutateur "-v" qui permet de réaliser un test de validité de signature sur une assembly :

info Remarque : le commutateur "-vf" permet de forcer la vérification, même si celle-ci à été désactivée, comme nous l'avons montré un peu plus haut avec l'aide du commutateur "-Vr".

5.3. Le test key signing


5.3.1. Présentation

Avec le Framework .Net 2.0 est apparu une nouveauté en matière de signature d'assembly, il s'agît du "Test Key Signing" qui vient pour combler les "lacunes" du delay signing, qui je vous le rappelle vous obligent à désactiver la vérification de signature pour une assembly ou un jeton de clè publique donné, ce qui est une faille potentielle de la sécurité de votre poste de développement. De plus, désactiver la vérification de signature vous empêche d'avoir une idée exacte des performances de votre application (notamment lors de son chargement par le CLR) dans un environnement de production, en effet, il ne faut pas sous estimer le temps nécessaire pour les vérifications de de la signature. Meme si ces temps sont relativement courts, ils peuvent s'avérer déterminants pour des applications ayant des impératifs de performances. Pour palier cela, Microsoft à intégré une nouveauté dans le Framework 2.0, le Test Key Signing, voyons à quoi il correspond sans plus attendre.

Le "Test Key Signing" permet à la différence du delay signing de signer réellement son assembly, et donc de pouvoir effectuer le contrôle de signature lors du chargement de celle ci par l'environnement .Net ce qui peut être un avantage certain comme nous l'avons vu précédemment.

Pour "test signer" une assembly l'on procède de la façon suivante :

  • Signer l'assembly avec le procédé de signature différée (delay signing) en utilisant votre clé publique
  • Créer une paire de clés (publique/privée) de test avec sn.exe
  • Test signer l'assembly avec la paire de clé de test, c'est la clé privée de test qui va être utilisée pour la signature (utiliser sn.exe avec le commutateur -TS)
  • Configurer l'environnement d'exécution pour utiliser la clé publique pour vérifier la validité des assembly signée avec la clé privée de test (utiliser sn.exe avec le commutateur -Vr)
Votre assembly est à ce stade "test signée" avec la clé privée de test, et la validité de la signature est vérifiée grâce à votre clé publique habituelle. Clé publique que vous aurez pris le soin d'extraire de la paire clé publique/privée que vous utilisez pour signer vos assemblies, en effet, l'objectif de tout cela est la protection de la clé privée.

Une fois le développement terminé il ne restera plus qu'à signer définitivement votre assembly avec la clé privée que vous avez gardée en sécurité depuis le début. Cela doit être réalisé avec l'utilitaire sn.exe et avec le commutateur -R ou -Rc en fonction de vos besoins.


5.3.2. Démonstration

Voici un schéma montrant le processus complet de "Test Signing" jusqu'à la signature finale avec la clé privée que vous utilisez pour signer vos assemblies que vous aller livrer.

Test Key Signing

Ressources


Conclusion

Comme nous l'avons vu au cours de cet article, la signature d'assembly n'incarne pas à elle seule la sécurité du code de votre application, mais elle y participe. Si la signature complète d'assemblies lors de gros développements n'est pas adaptée, notamment en ce qui concerne la protection de la clé privée. Pour palier à ces faiblesses il existe le "Delay Signing", et depuis le Framework .Net 2.0, le "Test Key Signing", qui pour moi semble être la meilleure solution à l'heure actuelle, apportant flexibilité et confidentialité de la clé privée.

J'espère au cours de cet article vous avoir montré aussi simplement que possible tout l'intérêt que vous pouvez trouver dans ce procédé, pas si évident que cela à appréhender, qu'est la signature d'assembly. Enfin, pour terminer, gardez toujours à l'esprit qu'aucune méthode isolée n'est suffisante pour apporter une sécurité efficace, seule l'addition de différents niveaux de sécurisation amène une réponse convenable.

Un grand merci à Khany pour la relecture de cet article, ainsi qu'à l'équipe Dotnet pour son aide.



Valid XHTML 1.1!Valid CSS!

Les sources présentées sur cette page sont libres de droits, et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une oeuvre intellectuelle protégée par les droits d'auteurs. Copyright © 2006 Ronald Vasseur. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à 3 ans de prison et jusqu'à 300 000 E de dommages et intérêts. Cette page est déposée à la SACD.

Responsable bénévole de la rubrique DotNET : Jérôme Lambert (Cardi) - Contacter par EMail :
Vos questions techniques : forum d'entraide DotNET - Publiez vos articles, tutoriels et cours
et rejoignez-nous dans l'équipe de rédaction du club d'entraide des développeurs francophones
Nous contacter - Copyright © 2000-2008 www.developpez.com - Legal informations.