web-dev-qa-db-fra.com

Ajout d'un certificat qui réside sur SmartCard vers Microsoft Store avec la clé privée

Comment pouvons-nous résoudre CryptAcquireCertificatePrivateKey échoue avec 0x8009200B Lorsque vous ajoutez un certificat de SmartCard au magasin d'utilisateurs locaux?

Dans un système d'inscription où les utilisateurs génèrent des demandes de certificat SmartCard en ligne à une autorité de certification, le certificat est chargé "hors ligne" dans la carte à puce, par exemple plusieurs jours après la publication de la demande afin que les objets certenrolllib utilisés pour la création du La demande ne peut pas être utilisée pour installer le certificat sur la carte et la carte générée la clé privée qui ne sera jamais et ne peut être exportée en dehors de la carte.

Lorsque nous chargons le certificat de la carte, nous utilisons l'API Minidriver, nous avons le nom du conteneur de clé qui a été utilisé pour la génération de la clé (généralement un GUID, quelque chose comme lr-e46f1586-7133-4284-895d-557e2261c24d) Nous commençons à lire le CMAPFile et nous obtenons l'index KeContainer XX qui correspond à cela GUID et nous créons un certificat KSCXX dans le dossier MSCP dans le système de fichiers Minidriver de la carte, nous compressons avec zlib Le certificat binaire DER obtenu à partir de l'autorité de certification, nous ajoutons un en-tête et nous chargons cela sur le fichier KSCXX.

Nous pouvons voir que le certificat de carte sur carte est bien formé et que nous pouvons le voir à l'aide de divers outils. Le problème est que ce certificat n'apparaît pas dans le magasin d'utilisateurs Microsoft. En fait, il "peut" apparaître parfois surtout si le conteneur est le conteneur par défaut, mais de toute façon, pas immédiatement et non dans tous les systèmes d'exploitation.

Nous avons créé une LIB utilisant MSCAPI qui obtiennent le contexte de certificat et qui prouve une clé privée en utilisant Crypttacquirecertificateprivatekey dans le code suivant (utilisé à Say: addCardcertostore.exe outil par exemple)

Journalisation avec code PIN, obtention de la clé USBKey, etc.

 fStatus = CryptGetKeyParam(
    hKey,                  // HCRYPTKEY hKey,
    KP_CERTIFICATE,        // DWORD dwParam,
    pCertBlob,             // BYTE* pbData,
    &dwCertLen,            // DWORD* pdwDataLen,
    0                      // DWORD dwFlags
    );

if (!fStatus)
{
    return 1;
}


pCertContext = CertCreateCertificateContext(
    PKCS_7_ASN_ENCODING | X509_ASN_ENCODING,
    pCertBlob,
    dwCertLen);

    //trying to prove privatekey ownership by calling CryptAcquireCertificatePrivateKey


HCRYPTPROV_OR_NCRYPT_KEY_HANDLE  hCrypt;

    DWORD  hInfo;

fStatus=CryptAcquireCertificatePrivateKey(pCertContext,0,NULL,&hCrypt,&hInfo,NULL);

     if (!fStatus)
{
     return 1;
}



    hStoreHandle = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, 0, CERT_SYSTEM_STORE_CURRENT_USER, L"My");

// Sauvegarde du contexte de certificat à stocker

Si CryptAcquireCertificatePrivateKey n'est pas appelé, le certificat est toujours exporté pour stocker, mais sans capitale privée, puis ne peut pas être utilisé pour des opérations telles que la signature, etc.

Cependant, lorsque nous utilisons CryptAcquireCertificatePrivateKey50% des temps ", nous pouvons enregistrer le certificat pour stocker avec la propriété privée, mais pas toujours, dans plusieurs cas, nous voyons 0x8009200B Erreur (crypt_e_no_key_property, par exemple, ne peut pas trouver le certificat et la clé privée du décryptage. ') Lorsque vous appelez CryptAcquireCertificatePrivateKey. Cette erreur peut arriver, par exemple, la première fois que nous lançons le addcardcertostore.exe alors si nous redémarrons addCardcerttOstore.exe une seconde fois qu'il peut fonctionner, CryptAcquireCertificatePrivateKey renvoie OK, et le certificat est installé dans le magasin, parfois nous devons parfois Appelez-le trois fois, parfois, il semble que cela ne fonctionnera jamais et cela fonctionne parfois après que nous réinsérons la carte, il échoue parfois car le certificat a été installé automatiquement après un certain temps dans le magasin et en supprimant ce certificat CryptAcquireCertificatePrivateKey fonctionne et Ajoutez à nouveau le certificat sur le magasin.

Je sais que le CSP maintient une cache et qu'elle scanne périodiquement la carte pour mettre à jour ce cache et qu'il peut ne pas détecter un nouveau certificat sur la carte et l'ajouter au magasin seul et que certaines opérations MSCAPI peuvent avoir l'effet de Avoir le CSP mettant à jour le magasin depuis les certificats de la carte indépendamment de l'opération elle-même.

À la fin de la question, la question est la suivante: pourquoi un comportement aussi étrange de CryptAcquireCertificatePrivateKey et comment pouvons-nous interpréter le code d'erreur 0x8009200B (accès refusé) dans ce contexte?
[.____
[.____] Comment pouvons-nous avoir un moyen stable d'ajouter le certificat de carte au magasin?

6
user49920

Ces choses peuvent être un peu complexes car il y a beaucoup de morceaux au puzzle et cache partout.

La théorie est que vous devez utiliser Certenroll (fourni par le système d'exploitation) et laissez-le faire toute la magie. Certenroll peut parfaitement soutenir un long délai (même plusieurs jours) entre la génération de demande et l'importation de certificats; Toutefois, la génération de demande et l'importation de certificats suivants doivent être effectuées une seule machine, avec le même compte. La raison en est que Certenroll conserve une trace d'une opération d'inscription en cours en enregistrant une copie de la requête elle-même dans un magasin dédié (en dehors de la carte) qui lui permet, lorsque le certificat revient, pour localiser la clé privée et définir tous les liens.

(Théoriquement, si l'opération est effectuée en tant que "utilisateur normal" sur ses magasins, pas la machine locale stocke, la demande doit alors se retrouver dans le "profil d'itinérance", supprimant ainsi la nécessité d'utiliser le même machine; seulement la condition sur le compte est maintenu. Cela nécessiterait des tests, cependant.)

La pratique peut différer pour un certain nombre de raisons. Peut-être que l'installation de certificat est effectuée sur un système matériel dédié, par exemple. Si vous ne pouvez pas utiliser Certenroll, ou si un cache est faux (cela se produit), vous devez alors prendre en compte les points suivants:

  • Le lien de certificat à la clé privée est quelque chose qui se produit sur le côté Windows des choses. Lorsque vous appelez crypttacquirecertificateprivatekey () , il suit réellement une propriété du Certiers context, c'est-à-dire l'objet côté Windows, pour localiser le nom de CSP et du conteneur dans ce csp . En interne, cette propriété consiste dans le csp nom et le nom du conteneur. Vous pouvez la définir avec CertSetCertificatCatecontextProperty () ; utilisation CERT_KEY_PROV_INFO_PROP_ID.

    Une telle propriété est normalement persistante (elle est écrite dans la structure du magasin, normalement quelques fichiers au profil d'itinérance de l'utilisateur), mais vous pouvez le garder dans RAM uniquement avec CERT_SET_PROPERTY_INHIBIT_PERSIST_FLAG. Lorsque la propriété est définie dans RAM uniquement, il n'aura qu'un impact sur un CERT_CONTEXT Structure et seront bien sûr limitées à un seul processus.

  • Sur la carte, la relation entre certificat et clé privée est conservée différemment, avec le cmapfile et kxc* Fichiers, comme décrit dans les Spécifications de l'API Minidriver . Lorsque vous insérez la carte dans un système Windows, ce système est censé inspecter la carte pour les certificats et les pousser dans le magasin de l'utilisateur local et définir les liens vers des clés privées. Le "Service de propagation du certificat" fait cela, alors assurez-vous qu'il est démarré sur votre système. Sinon, cette extraction automatique des certificats ne fonctionnera pas.

    La "propagation de certificat" est déclenchée lorsque la carte est insérée. Si vous modifiez le contenu de la carte, surtout lorsque vous le faites "directement", vous devez demander à l'utilisateur de débrancher/repliquer la carte. La seule autre méthode que je suis consciente de déclencher la propagation du certificat est d'arrêter et de redémarrer le service de propagation de certificat, qui nécessite des privilèges d'administrateur.

    La propagation des certificats est asynchrone et peut prendre un temps substantiel (jusqu'à une minute environ), en particulier en conjonction avec un bureau distant et lorsque plusieurs lecteurs de cartes USB sont utilisés simultanément.

  • Il y a un cache. Le "Service de carte à puce" (Scardsvr.exe) le maintient. Le cache est basé sur la RAM, mais le service l'écrit dans un registre lorsqu'il s'arrête, le cache résiste aux redémarrages (la clé de registre est HKLM\SOFTWARE\Microsoft\Cryptography\Calais\Cache\Cache).

    Le cache est censé accélérer les choses: la lecture des données de la carte contient des E/S lents. Les certificats, les noms de conteneurs, même des clés publiques sont stockés dans le cache. Il est crucial que le cache soit maintenu synchronisé, sinon divers problèmes se produisent, ce qui est compatible avec les symptômes que vous décrivez (vous pouvez également obtenir d'autres personnes, par exemple NTE_BAD_SIGNATURE lors de l'informatique, car le BASECSP veut Vérifiez une signature juste calculée et le fera avec la clé publique du cache, pas de la carte).

    Si le cache est considéré comme à jour dépend du contenu du fichier cardcf sur la carte. Ceci est décrit à la section 5.4.3 de l'API Minidriver. Fondamentalement, ce fichier contiendra deux compteurs de 16 bits, un pour le contenu du conteneur (c'est-à-dire les touches publiques), une autre pour les fichiers. Si vous modifiez un conteneur (par exemple, générer ou importer une nouvelle paire de clés) ou n'importe quel fichier (et vous le faites!), Alors vous [~ # ~ # ~] incrémente le ou les contre-compteurs pertinents dans cardcf. Normalement, le BASECSP le fait automatiquement en cas de besoin, mais si vous réinitialisez une carte, ou de le modifier éternellement, vous devrez peut-être le faire manuellement (j'ai personnellement été témoins de bugs dans le cache Scardsvr, donc j'ai aussi fini par forcer un cardcf mise à jour avec les commandes APDU spécifiques à la carte).

    Vous pouvez également essayer de configurer la carte de manière à ce qu'aucun cache ne soit maintenu pour ses informations; chercher CP_CARD_CACHE_MODE Dans l'API Minidriver. Toutes les cartes ne prennent pas en charge la modification du mode de cache, cependant.

  • Composer la situation déjà complexe est CNG . C'est une nouvelle API cryptographique. Il y a des ponts entre Cryptoapi et GNC; par exemple. les CRYPT_ACQUIRE_ALLOW_NCRYPT_KEY_FLAG pour crypttacquirecertificateprivatekey (). Lors de la définition de CERT_KEY_PROV_INFO_PROP_ID Propriété, vous voudrez peut-être remplacer le nom de Cryptoapi BasEpSP ("Fournisseur de Crypto Microsoft Base Smart Card Crypto") avec le nom Cryptong correspondant ("Fournisseur de stockage de clé de la carte Smart Microsoft Smart Card"). Cela peut confondre certaines applications qui ne sont pas au courant de la GNC.

    Jouer avec Cryptoapi et GNC peuvent être rendus nécessaires en ce qui concerne la carte PIN HANDINGLING. Afin de faciliter les opérations des utilisateurs, Cryptoapi et GNG maintiennent une mémoire cache en mémoire de la broche de l'utilisateur. . Cependant, les deux caches sont distinctes! De plus, avec une carte récente (c'est-à-dire celle qui prend en charge Minidriver V7, par opposition à Minidriver V5), il existe une "broche de session", générée automatiquement et les caches conserveront une copie de la session. Goupille, pas le PIN tel que connu de l'utilisateur humain. Si deux sous-ensembles de votre application utilisent la carte, une via Cryptoapi, l'autre avec GNG, alors ils seront en concurrence pour le code PIN, chacun déclencher la génération d'une nouvelle session PIN qui invalide la session PIN pour l'autre. La conséquence est répétée "Entrée de code PIN" jetée à l'utilisateur, qui est rarement heureux à ce sujet.

    En particulier, Internet Explorer sur Windows 7 et plus généralement le code client SSL, lors de l'accès à la clé privée de l'authentification client basée sur les certificats, a tendance à forcer l'utilisation du GNC. Si vous utilisez la même clé, dans la même application (par exemple, une commande ActiveX chargée dans IE), vous devez également utiliser GNC également - sinon, le PIN rage.

6
Thomas Pornin