CryptoAPI de Windows: CryptSignHash avec CALG_SHA_256 et la clé privée à partir de MON fichier de clés
Je suis en train de générer des signatures numériques sur Windows (XP SP3, mais actuellement à l'essai avec Windows 7) avec CryptoAPI qui sera compatible avec les commandes:
openssl dgst -sha256 -sign <parameters> (for signing)
openssl dgst -sha256 -verify <parameters> (for validation)
Je veux utiliser une clé privée à partir de la fenêtre "MON" magasin de clés de signature.
J'ai réussi à signer des fichiers en utilisant le SHA1 digérer par l'algorithme à l'aide de la suite de fonctions CryptoAPI (en omettant les paramètres par souci de concision):
CertOpenStore
CertFindCertificateInStore
CryptAcquireCertificatePrivateKey
CryptCreateHash (with CALG_SHA1)
CryptHashData
CryptSignHash
Générés signature est compatible avec "openssl dgst-sha1 -vérifier" (une fois que l'ordre des octets est inversée).
Mon problème: quand j'essaie d'utiliser CALG_SHA_256 avec CryptCreateHash, il échoue avec l'erreur 80090008 (NTE_BAD_ALGID). Par googler autour de, j'ai trouvé que j'avais besoin d'utiliser un fournisseur spécifique (PROV_RSA_AES) au lieu de celui par défaut. Depuis que j'aurais un fournisseur de poignée, j'aurais aussi besoin de remplacer CryptAcquireCertificatePrivateKey par CryptGetUserKey. J'ai donc modifié mon programme ressemble à:
CryptAcquireContext (with PROV_RSA_AES)
CertOpenStore
CertFindCertificateInStore
CryptGetUserKey
CryptCreateHash (with CALG_SHA256)
CryptHashData
CryptSignHash
Malheureusement, cela n'a pas fonctionné comme prévu: CryptGetUserKey a échoué avec l'erreur 8009000D (NTE_NO_KEY). Si je supprime le CryptGetUserKey appel, le programme s'exécute jusqu'à ce que CryptSignHash, qui échoue avec l'erreur 80090016 (NTE_BAD_KEYSET). Je sais que le jeu de clés en, existe et fonctionne très bien, depuis que j'ai été capable de l'utiliser pour signer le SHA1 digérer.
J'ai essayé d'acquérir le contexte nouveau avec des informations sur le contexte du certificat que j'ai eu de CertFindCertificateInStore: le meilleur que j'ai pu faire a été un succès CryptGetUserKey appel, mais CryptSignHash serait échoue toujours avec la même erreur.
La clé privée, je suis en train d'utiliser est de 2048 bits, mais je ne vous attendez pas à être un problème puisqu'il fonctionne avec le SHA1 digérer. Je suis à une perte, de sorte que toute suggestion est la bienvenue!
OriginalL'auteur Dominique Eav | 2010-11-16
Vous devez vous connecter pour publier un commentaire.
Le problème est plus probable que les certificats sur Windows "savoir", dans lequel le fournisseur de leurs clés privées sont stockées. Lorsque vous importez vos cert il aurait mis la clé dans un certain type de fournisseur (probablement PROV_RSA_FULL), lorsque vous essayez ultérieurement pour accéder à la clé via le certificat, il sera probablement jusqu'à la fin dans le même type de fournisseur.
Vous avez probablement besoin d'ouvrir le contexte associé pour le certificat (avoir un coup d'oeil à CertGetCertificateContextProperty avec le CERT_KEY_PROV_HANDLE_PROP_ID option).
Avec cette poignée yyou pourrait tenter d'exporter la clé de l'origine fournisseur de contexte et de réimportation dans une nouvelle PROV_RSA_AES un (en supposant que la clé est exportable).
Eav Avez-vous trouvé la solution?", si la clé n'est pas exportable" j'ai le même problème...
si la clé n'est pas exportable... alors, il n'est pas possible, je le crains.
OriginalL'auteur tyranid
80090008
est causée en raison de la Base de fournisseur ne prend pas en charge SHA256, SHA384 et SHA512, vous devez utiliserCryptAcquireContext(hProv, NULL, MS_ENH_RSA_AES_PROV, PROV_RSA_AES, 0);
OriginalL'auteur Delphi
La plupart des réponses précédentes parties de la réponse réelle. La façon de le faire est d'obtenir un HCRYPTPROV qui utilise le conteneur de clé et le "Microsoft Enhanced RSA et AES Fournisseur de services de Chiffrement" en appelant
L'résultant hCryptProv peut être utilisé pour signer les hachages créé avec tous les SHA2: 256, 384, 512.
Le Nom du Conteneur de Clé peut être obtenue soit avec CertGetCertificateContextProperty() avec l'argument CERT_KEY_PROV_INFO_PROP_ID si la clé est obtenue par le certificat, ou par CryptGetProvParam() avec l'argument PP_CONTAINER si il y a déjà un HCRPYPTPROV pour cette clé ( par exemple, obtenu avec CryptAcquireCertificatePrivateKey).
Cette technique fonctionne, même si la clé privée n'est pas exportable.
OriginalL'auteur 255
Une fois que vous avez trouvé le certificat, essayez d'appeler
CertGetCertificateContextProperty
avecCERT_KEY_PROV_INFO_PROP_ID
pour obtenir le nom du fournisseur et de récipient avec la clé.Essayez d'appeler
CryptAcquireContext
avec ces noms, mais la spécificationPROV_RSA_AES
que le type de fournisseur.Vous pourriez aussi essayer de remplacer le nom du fournisseur avec "Microsoft Enhanced RSA et AES Fournisseur de services de Chiffrement", mais ce ne sera certainement pas de travail, sauf si le fournisseur est l'un de l'autre Microsoft fournisseurs.
Désolé, vous avez raison. Je ne pense pas que vous pouvez le faire de cette façon. Je vais écrire une autre suggestion, vous pouvez essayer.
Vae: j'ai mis à jour la réponse avec une autre suggestion.
J'avais essayé, et j'ai essayé de nouveau après la mise à jour de votre réponse, mais il ne semble pas fonctionner dans mon cas (encore NTE_BAD_KEYSET).
OriginalL'auteur Rasmus Faber
J'ai rencontré un problème similaire récemment, avant j'ai trouvé ce post. Bien que ce post est utile dans la compréhension du problème, il n'a pas donner une solution. Enfin, avec l'aide de Google, j'ai résolu le problème. Bien que cette question a été posée il y a 5 ans, j'écris ma solution ici dans le cas où il aidera n'importe quel autre gars.
Tout d'abord, laissez-moi vous décrire mon problème: Nous avons porté OpenSSL 0.9.8 sur notre dispositif agissant comme un serveur SSL, alors que nous avons également fourni un programme s'exécutant sur Microsoft Windows en tant que client SSL, qui est également à l'aide de bibliothèque OpenSSL. Ce modèle client/serveur supportant l'authentification par certificat client. L'appel du client Microsoft Crypto-API de mise en œuvre de RSA_method dans OpenSSL pour soutenir le certificat d'authentification. Pour l'instant, donc bon avant de nous la mise à niveau de la bibliothèque OpenSSL de 0.9.8 à 1.0.2 pour soutenir TLSv1.2. Avec TLSv1.2 choisi, l'authentification du certificat client toujours échoué. Après le débogage, j'ai trouvé le problème est dans la RSA_sign méthode du programme client. Cette méthode signer le résultat du hachage pour obtenir la signature numérique, qui sera utilisée dans le protocole SSL, le Client de Vérifier le message. L'opération de signature est calculée à l'aide de
CertFindCertificatePrivateKey/CryptCreateHash/CryptSetHashParam/CryptSignHash
Api que cette question est décrit. L'erreur s'est produite dans le CryptCreateHash d'appel, où l'demandé méthode de hachage est SHA-384, mais le hCryptoProv récupérées par CertFindCertificatePrivateKey correspondait à une CSP (Microsoft Enhanced Cryptographic Provider v1.0) ne prend PAS en charge SHA-2 méthodes de hachage.C'est un vrai fastidieuse description. Si vous êtes toujours en continuer la lecture, je suppose que vous avez rencontré un problème similaire. Permettez-moi de vous présenter ma solution.
Ma première réaction a été d'ajuster la négociation SSL param de déclasser l'algorithme de hachage SHA-1, mais j'ai échoué. Il semble SHA-2 de hachage est obligatoire pour TLSv1.2. Aussi ai-je essayer d'atteindre le signe de l'opération par le chiffrement avec la clé privée du certificat, qui a été aussi échoué. Crypto-API fournit PAS d'interface pour le certificat de chiffrement à clé privée (je ne suis pas sûr de cela, mais je n'ai pas trouvé.) Après deux jours de resultless essayer, j'ai trouvé cette page: http://www.componentspace.com/Forums/Topic1578.aspx. C'est vraiment comme la lumière au bout du tunnel. Le certificat est obligatoire avec un CSP ne pas soutenir SHA-2, si l'on peut convertir en un CSP soutenir SHA-2, tout sera OK. En cas de rupture de lien, je colle la conversion de la méthode ici:
Je viens de reconstruit le .pfx du fichier de certificat de la page web dit; re-importé le certificat. Alors le problème est résolu.
Espère que cela est utile. 🙂
OriginalL'auteur GrepAll