Partager via


Guide de développement pour les enclaves de sécurité basée sur la virtualisation (VBS)

Ce guide de développement explique comment générer, signer et déboguer une enclave VBS de base.

Prérequis

Pour commencer avec les enclaves VBS, vous devez répondre aux exigences suivantes :

  • Consultez et répondez aux exigences de l’appareil dans la vue d’ensemble des enclaves VBS.
  • Consultez et répondez aux conditions préalables de l’appareil dans la vue d’ensemble des enclaves VBS.
    • Il est recommandé d’installer la charge de travail Développement Desktop avec C++ via le programme d’installation de Visual Studio. Elle installe tous les outils nécessaires, y compris le Kit de développement logiciel (SDK) Windows.
  • Téléchargez l’exemple de code de GitHub. Il montre le cycle de vie d’une enclave VBS, notamment comment effectuer des appels de fonction dans l’enclave.
    • Chaque enclave doit avoir une application hôte. L’exemple de code contient une solution Visual Studio avec deux projets : l’hôte d’enclave et l’enclave de test.

Mise en route

Après avoir satisfait aux conditions préalables ci-dessus, vous devez être en mesure d’ouvrir le fichier de solution à partir de l’exemple VbsEnclave dans Visual Studio et de le compiler. Il crée une application de test avec l’enclave correspondante. Toutefois, vous ne pouvez pas exécuter votre application correctement tant que l’enclave n’est pas signée avec un certificat valide.

Ce guide explique comment créer une enclave VBS de base sur votre appareil de développement. Les étapes de création d’une enclave VBS sont les suivantes :

  1. Écrire une DLL d’enclave VBS et une application hôte correspondante
  2. Compiler la DLL et l’hôte
  3. Signer la DLL d’enclave VBS
  4. Déboguer l’enclave VBS

Commençons par comprendre le cycle de vie d’une enclave. Les API d’enclave sont appelées dans l’ordre suivant :

Diagramme illustrant l’ordre dans lequel les API d’enclaves VBS sont appelées

Étape 1 : Écriture d’enclaves VBS

Examinons l’exemple de code et comprenons comment écrire une application qui utilise une enclave VBS.

Écriture de l’hôte d’enclave

N’oubliez pas qu’une DLL d’enclave VBS est simplement une DLL et nécessite donc une application hôte. L’application hôte n’est qu’une application Windows standard. Pour utiliser des enclaves VBS, l’hôte doit utiliser les API d’enclave Windows à partir de l’en-tête enclaveapi.h. L’inclusionde windows.h dans votre application hôte fournit l’accès à ces API.

Écriture de la DLL à charger dans une enclave de test

Reportez-vous à l’exemple de code dans le projet test d’enclave pour suivre les étapes ci-dessous.

Dans notre exemple d’enclave, nous créons une enclave simple qui OUX l’entrée avec 0xDADAF00D et retourne le résultat. Voyons comment procéder :

  1. Commencez par inclure winenclave.h. Dans l'exemple de code, reportez vous à Samples/VbsEnclave/Test enclave/precomp.h:

    #include <winenclave.h>
    

    winenclave.hest le fichier include central pour les enclaves VBS et inclut lui-même windows.h, ntenclv.h, winenclaveapi.h.

  2. Chaque DLL chargée dans une enclave nécessite une configuration. Cette configuration est définie à l’aide d’une variable globale const nommée __enclave_config de type IMAGE_ENCLAVE_CONFIG. Dans l'exemple de code, reportez vous à Samples/VbsEnclave/Test enclave/enclave.c:

    const IMAGE_ENCLAVE_CONFIG __enclave_config = {
        sizeof(IMAGE_ENCLAVE_CONFIG),
        IMAGE_ENCLAVE_MINIMUM_CONFIG_SIZE,
        IMAGE_ENCLAVE_POLICY_DEBUGGABLE,    // DO NOT SHIP DEBUGGABLE ENCLAVES TO PRODUCTION
        0,
        0,
        0,
        { 0xFE, 0xFE },    // family id
        { 0x01, 0x01 },    // image id
        0,                 // version
        0,                 // SVN
        0x10000000,        // size
        16,                // number of threads
        IMAGE_ENCLAVE_FLAG_PRIMARY_IMAGE
    };
    

    Remarque

    Il ne peut y avoir qu’une seule image principale par enclave. Si vous chargez plusieurs images primaires, celle chargée en premier est traitée comme primaire et les autres sont traitées comme des dépendances. Dans cet exemple, il n’existe aucune dépendance autre que les DLL de plateforme d’enclave.

  3. La fonction DllMain() est obligatoire et définit le point d’entrée dans l’enclave. elle est appelée durant InitializeEnclave(). Dans l'exemple de code, reportez vous à Samples/VbsEnclave/Test enclave/enclave.c.

    BOOL
    DllMain(
        _In_ HINSTANCE hinstDLL,
        _In_ DWORD dwReason,
        _In_ LPVOID lpvReserved
    )
    {
        UNREFERENCED_PARAMETER(hinstDLL);
        UNREFERENCED_PARAMETER(lpvReserved);
    
        if (dwReason == DLL_PROCESS_ATTACH) {
            InitialCookie = 0xDADAF00D;
        }
    
        return TRUE;
    }
    
  4. Toutes les fonctions à l’intérieur de l’enclave appelées à partir de l’application hôte doivent être exportées et être de type LPENCLAVE_ROUTINE. La signature de la fonction se présente comme suit :

    void* CALLBACK enclaveFunctionName(_In_ void* Context)
    

    Dans l'exemple de code, reportez vous à Samples/VbsEnclave/Test enclave/enclave.c.

    void*
    CALLBACK
    CallEnclaveTest(
        _In_ void* Context
    )
    {
        WCHAR String[32];
        swprintf_s(String, ARRAYSIZE(String), L"%s\n", L"CallEnclaveTest started");
        OutputDebugStringW(String);
    
        return (void*)((ULONG_PTR)(Context) ^ InitialCookie);
    }
    

    Remarque

    Seules les fonctions exportées par l’image d’enclave principale sont accessibles à partir de l’application hôte.

    Vous pouvez ensuite exporter la fonction en utilisant le fichier .DEF. Dans l'exemple de code, reportez vous à Samples/VbsEnclave/Test enclave/vbsenclave.def. Pour plus d’informations, reportez vous à exportation à partir d’une DLL à l’aide de fichiers DEF.

Et c’est ainsi que vous écrivez une DLL d’enclave VBS de base.

Étape 2 : Compilation d’enclaves VBS

Maintenant que nous avons écrit notre DLL d’enclave VBS, compilons-la.

Compilation de l’hôte d’enclave

La compilation de l’application hôte est identique à la compilation de n’importe quelle application Windows, mais avec l’ajout de onecore.lib à la liste des dépendances lors de la liaison.

Compilation de la DLL d’enclave de test

Avant de pouvoir créer la DLL d’enclave de test, quelques modifications des configurations du compilateur et de l’éditeur de liens sont nécessaires :

  1. L’éditeur de liens MSVC fournit un indicateur /ENCLAVE qui récupère les détails de configuration de l’enclave. L’indicateur /ENCLAVE n’est pas compatible avec la liaison incrémentielle. Nous devons donc définir /INCREMENTAL:NO.

  2. [Configuration de débogage uniquement] /EDITANDCONTINUE est incompatible avec /INCREMENTAL:NO, donc nous utilisons /Zi au lieu de /ZI pour Format des informations de débogage dans le compilateur.

  3. [Configuration de débogage uniquement] La configuration Vérifications de base à l’exécution doit être définie sur Par défaut. Les vérifications des erreurs d’exécution ne sont pas prises en charge dans les enclaves VBS.

  4. La signature numérique d’une DLL d’enclave doit être vérifiée au moment du chargement et nécessite de définir l’indicateur /INTEGRITYCHECK dans l’éditeur de liens.

  5. Les DLL d’enclave doivent être instrumentées pour laprotection du flux de contrôle (CFG) pour laquelle nous utilisons l’indicateur /GUARD:MIXED dans l’éditeur de liens.

  6. Les enclaves ont leurs propres versions de la plateforme, du démarrage, du runtime et des bibliothèques UCRT. Pour nous assurer que nous ne liez pas les versions non enclave, utilisez l’indicateur /NODEFAULTLIB . Ensuite, ajoutez les bibliothèques correctes sous AdditionalDependencies. Dans l’exemple de code, ces bibliothèques sont encapsulées sous la macro VBS_Enclave_Dependencies . Voici les bibliothèques d’enclave VBS :

    1. libcmt.lib et libvcruntime.lib - Trouvé dans le dossier enclave avec les outils de génération Visual C++, consultez les fichiers .lib C runtime (CRT) et C++ standard library (STL).
    2. vertdll.lib et bcrypt.lib - Trouvé dans le dossier um avec les bibliothèques du Kit de développement logiciel (SDK) Windows.
    3. ucrt.lib - Trouvé dans le dossier ucrt_enclave avec les bibliothèques du Kit de développement logiciel (SDK) Windows.

Remarque

Aucune autre bibliothèque de plateforme n’est prise en charge dans les enclaves VBS.

Dans le résumé, les modifications suivantes sont requises :

Compilateur (configuration de débogage uniquement) :

  • Format des informations de débogage : /Zi
  • Vérifications de base à l’exécution : Default

Linker :

  • /ENCLAVE
  • /NODEFAULTLIBS + AdditionalDependencies
  • /INCREMENTAL:NO
  • /INTEGRITYCHECK
  • /GUARD:MIXED

Vous pouvez maintenant compiler la DLL d’enclave.

Sécurisation avec VEIID

VEIID, l’utilitaire de liaison d’ID d’importation d’enclave VBS, est un outil du Kit de développement logiciel (SDK) Windows qui met à jour les tables d’importation à l’intérieur d’une enclave VBS avec des ID connus pour les DLL de plateforme. Cela améliore la sécurité des enclaves VBS en empêchant le chargement d’une DLL malveillante (signée) portant le même nom que l’une des DLL de plateforme.

Dans l’exemple de code, cette opération est effectuée automatiquement en tant qu’événement post-build.

Remarque

Il est fortement recommandé d’éviter d’utiliser vos propres DLL non principales, à l’exception des DLL de la plateforme. Au lieu de cela, conservez tout votre code dans la DLL d’enclave elle-même.

Étape 3 : Signature des DLL d’enclave VBS

Les enclaves VBS doivent être signées pour être correctement chargées. La signature d’une enclave contient des informations sur l’auteur de l’enclave. Il est utilisé pour dériver l’ID d’auteur d’une enclave. Vous pouvez tester la signature de votre enclave avant de la signer pour la production.

Signature test – Local

Chaque certificat de signature d’enclave nécessite au moins 3 utilisations améliorées de clé (EKU) :

  1. Référence EKU de signature de code - 1.3.6.1.5.5.7.3.3

  2. Référence EKU de l’enclave - 1.3.6.1.4.1.311.76.57.1.15

  3. Référence EKU Auteur - La référence EKU est de la forme 1.3.6.1.4.1.311.97.X.Y.Z, où X est supérieure à999.

    Pour les tests, vous pouvez choisir d’utiliser n’importe quelle référence EKU Auteur qui correspond à ce modèle. Pour la production, une référence EKU d’auteur est fournie dans le cadre du certificat de production (plus d’informations sur la signature de production ci-dessous).

    Exemple : 1.3.6.1.4.1.311.97.814040577.346743379.4783502.105532346

Si vous souhaitez signer votre DLL d’enclave lors du développement, activez le test de signature. Une fois le test de signature activé, vous pouvez créer un certificat contenant ces trois EKU et signer votre enclave avec celle-ci. Utilisez l’applet de commande New-SelfSignedCertificate pour créer un certificat. Notez que les DLL d’enclave doivent être signées par hachage de page.

Remarque

Une fois que vous avez un certificat, vous pouvez automatiser le processus de signature dans l’événement post-build.

New-SelfSignedCertificate -CertStoreLocation Cert:\\CurrentUser\\My -DnsName "MyTestEnclaveCert" -KeyUsage DigitalSignature -KeySpec Signature -KeyLength 2048 -KeyAlgorithm RSA -HashAlgorithm SHA256 -TextExtension "2.5.29.37={text}1.3.6.1.5.5.7.3.3,1.3.6.1.4.1.311.76.57.1.15,1.3.6.1.4.1.311.97.814040577.346743379.4783502.105532346"
signtool sign /ph /fd SHA256 /n "MyTestEnclaveCert" vbsenclave.dll

Une fois votre DLL d’enclave signée, vous pouvez désormais la charger dans un environnement sur lequel la signature de test est activée.

Signature de production – Signature de confiance (anciennement signature de code Azure)

La signature de production pour les enclaves est fournie via le profil de certificat d’enclave VBS dans la signature de confiance. Pour plus d’informations sur l’utilisation de la signature approuvée, consultez la documentation.

La signature approuvée vous permet également de signer votre enclave sur la ligne de commande. Cela génère une enclave prête à l’exécution signée lorsque vous générez votre enclave dans Visual Studio.

Étape 4 : Débogage d’enclaves VBS

En règle générale, la mémoire d’une enclave est masquée des débogueurs et est protégée contre VTL0. Cependant, si vous souhaitez déboguer votre DLL d’enclave VBS, vous pouvez les créer pour qu’elles soient déboguées pendant le développement. Les enclaves sont un processus en mode utilisateur VTL1 et peuvent donc être déboguées avec un débogueur en mode utilisateur.

Pour permettre à votre enclave d’être débogué :

  1. La configuration de l’image de la DLL d’enclave doit permettre le débogage : cela se fait en définissant l’indicateur IMAGE_ENCLAVE_POLICY_DEBUGGABLE dans IMAGE_ENCLAVE_CONFIG.
  2. Le débogage doit être autorisé lors de la création de l’enclave. Pour ce faire, définissez l’indicateur ENCLAVE_VBS_FLAG_DEBUG dans la structure ENCLAVE_CREATE_VBS_INFO passée à l’appel CreateEnclave.

Pour déboguer votre enclave :

  1. Attachez le débogueur en mode utilisateur au processus hôte de l’enclave.
  2. Rechargez les symboles d’enclave une fois que le processus hôte a chargé l’image d’enclave en mémoire.
  3. Définissez des points d’arrêt sur les fonctions à l’intérieur de l’enclave. Le débogueur l’insère sur un appel d’enclave.

Vous pouvez également interrompre les points d’arrêt en mode utilisateur pour CreateEnclave, InitializeEnclave, etc. qui effectuent une étape supplémentaire dans le code correspondant dans ntdll.dll.

Remarque

N’utilisez jamais d’enclaves débogueables dans des environnements de production.

Avec cela, vous pouvez maintenant générer et déployer votre première enclave VBS. Si vous avez des questions, n'hésitez pas à contacter le service d'assistance aux développeurs de Windows.

Vue d’ensemble des enclaves d’application

Signatures de confiance Azure

en-tête enclaveapi.h

API disponibles dans les enclaves VBS