Windows CryptoAPI: CryptSignHash mit CALG_SHA_256 und privaten Schlüssel von MEINEM keystore
Ich versuche das erzeugen digitaler Signaturen auf Windows (ab XP SP3, aber derzeit getestet mit Windows 7) mit CryptoAPI-kompatibel mit dem folgenden openssl-Kommandos:
openssl dgst -sha256 -sign <parameters> (for signing)
openssl dgst -sha256 -verify <parameters> (for validation)
Möchte ich mit einem privaten Schlüssel aus der Windows - "MEINE" - keystore zum signieren.
Schaffte ich es zum signieren von Dateien verwenden der SHA1-digest-Algorithmus mit der folgenden CryptoAPI-Funktionen (weglassen von Parametern für die Kürze):
CertOpenStore
CertFindCertificateInStore
CryptAcquireCertificatePrivateKey
CryptCreateHash (with CALG_SHA1)
CryptHashData
CryptSignHash
Die erzeugte Signatur ist kompatibel mit "openssl dgst -sha1 -überprüfen" (einmal die byte-Reihenfolge Umgekehrt).
Mein problem ist: wenn ich versuche, mit CALG_SHA_256 mit CryptCreateHash, es schlägt fehl mit Fehler 80090008 (NTE_BAD_ALGID). Durch googeln um, ich fand, dass ich brauchte, um einen bestimmten Anbieter (PROV_RSA_AES) anstelle des Standard ein. Da hätte ich einen Anbieter Griff, würde ich auch ersetzen müssen CryptAcquireCertificatePrivateKey von CryptGetUserKey. Also modifizierte ich mein Programm so Aussehen:
CryptAcquireContext (with PROV_RSA_AES)
CertOpenStore
CertFindCertificateInStore
CryptGetUserKey
CryptCreateHash (with CALG_SHA256)
CryptHashData
CryptSignHash
Leider hat dies nicht wie erwartet funktioniert: CryptGetUserKey fehlgeschlagen mit Fehler 8009000D (NTE_NO_KEY). Wenn ich entfernen Sie die CryptGetUserKey nennen, das Programm läuft bis CryptSignHash, die schlägt fehl mit Fehler 80090016 (NTE_BAD_KEYSET). Ich weiß, der Schlüsselsatz ist vorhanden und funktioniert einwandfrei, da war ich in der Lage, es zu benutzen, um Zeichen der SHA1-digest.
Ich habe versucht, den Erwerb der Kontext wieder mit Informationen aus dem Zertifikat Zusammenhang habe ich von CertFindCertificateInStore: das beste was ich tun konnte, war eine erfolgreiche CryptGetUserKey nennen, aber CryptSignHash würde immer Fehler mit dem gleichen Fehler.
Den private key ich bin versucht, ist 2048 bit lang, aber ich erwarte nicht, dass es ein problem zu sein, da klappt es mit dem SHA1-digest. Ich bin an einem Verlust, so dass jeder Vorschlag wäre sehr willkommen!
InformationsquelleAutor Dominique Eav | 2010-11-16
Du musst angemeldet sein, um einen Kommentar abzugeben.
Das problem wird wahrscheinlich sein, die Zertifikate unter Windows "weiß", in dem Anbieter, Ihren privaten Schlüssel gespeichert werden. Wenn Sie importieren Sie Ihre cert würde es den Schlüssel in einer bestimmten Anbieters geben (wahrscheinlich PROV_RSA_FULL), wenn Sie dann später versuchen, Zugriff auf die Schlüssel über das Zertifikat, es wird wahrscheinlich am Ende in ein und demselben Anbieter geben.
Müssen Sie wahrscheinlich öffnen Sie das zugehörige Kontext für das Zertifikat (haben Sie einen Blick auf CertGetCertificateContextProperty mit der CERT_KEY_PROV_HANDLE_PROP_ID option).
Mit diesem handle Sie könnten versuchen, exportieren Sie den Schlüssel aus dem ursprünglichen Kontext-Anbieter und reimporting in eine neue PROV_RSA_AES ein (vorausgesetzt, der Schlüssel exportierbar).
Eav Haben Sie die Lösung gefunden? ", wenn Schlüssel nicht exportierbar" ich habe das gleiche problem...
wenn der Schlüssel nicht exportierbar... dann ist es nicht möglich, fürchte ich.
InformationsquelleAutor tyranid
80090008
verursacht wird, da der Base-provider nicht unterstützt SHA256, SHA384 und SHA512, Sie habeCryptAcquireContext(hProv, NULL, MS_ENH_RSA_AES_PROV, PROV_RSA_AES, 0);
InformationsquelleAutor Delphi
Meisten der bisherigen Antworten, die haben die Teile die richtige Antwort. Der Weg, dies zu tun ist, um eine HCRYPTPROV, verwendet die Schlüssel-container und der "Microsoft Enhanced RSA und AES Cryptographic Provider" durch den Aufruf
Den daraus resultierenden hCryptProv kann verwendet werden, um Zeichen-hashes erstellt mit allen unterstützten SHA2: 256, 384, 512.
Der Name des Schlüssel-Containers erhalten Sie entweder mit CertGetCertificateContextProperty() mit dem argument CERT_KEY_PROV_INFO_PROP_ID wenn der Schlüssel ist, die durch das Zertifikat oder durch CryptGetProvParam() mit dem argument PP_CONTAINER, wenn es bereits ein HCRPYPTPROV für die Taste ( zum Beispiel, die mit CryptAcquireCertificatePrivateKey).
Diese Technik funktioniert auch, wenn der private Schlüssel nicht exportierbar.
InformationsquelleAutor 255
Sobald Sie gefunden haben, das Zertifikat, versuchen Sie den Aufruf
CertGetCertificateContextProperty
mitCERT_KEY_PROV_INFO_PROP_ID
um den Namen von provider und der container mit dem Schlüssel.Versuchen Sie anrufen
CryptAcquireContext
mit diesen Namen, aber unter AngabePROV_RSA_AES
als der Anbieter geben.Könnten Sie auch versuchen, anstelle der provider-Namen, die mit "Microsoft Enhanced RSA und AES Cryptographic Provider", aber das wird definitiv nicht funktionieren, es sei denn, der Anbieter ist einer der anderen Microsoft-Anbieter.
Sorry, du hast Recht. Ich glaube nicht, können Sie es tun auf diese Weise. Ich werde schreiben, bis eine andere Anregung, die Sie ausprobieren können.
Eav: ich aktualisierte Antwort mit einem anderen Vorschlag.
Ich hatte dies versucht, und ich versuchte es erneut, nachdem Sie aktualisiert Ihre Antwort, aber es scheint nicht zu funktionieren in meinem Fall (noch NTE_BAD_KEYSET).
InformationsquelleAutor Rasmus Faber
Stieß ich auf ein ähnliches problem vor kurzem, bevor ich fanden diesen Beitrag. Obwohl, dieser Beitrag ist hilfreich beim Verständnis des Problems, es ist aber nicht eine Lösung. Schließlich, mit Hilfe von Google, habe ich das problem gelöst. Obwohl diese Frage wurde bereits vor 5 Jahren Schreibe ich meine Lösung hier im Fall wird es helfen, jeder andere Kerl.
Erste, lassen Sie mich beschreiben, mein problem: Wir haben portiert, OpenSSL 0.9.8 auf unserem Gerät als ein SSL-server, während wir auch eine Programm läuft auf Microsoft Windows als ein SSL-client, der auch mit der OpenSSL-Bibliothek. Dieses client/server-Modell, Unterstützung von client-Zertifikat-Authentifizierung. Der client rufen Sie die Microsoft Crypto-API implementieren RSA_method in OpenSSL zur Unterstützung der Zertifikat-Authentifizierung. So weit, So gut, bevor wir die Aktualisierung der OpenSSL Bibliothek von 0.9.8 auf Version 1.0.2 zu unterstützen TLSv1.2. Mit TLSv1.2 gewählt, das client-Zertifikat-Authentifizierung immer gescheitert. Nach debugging habe ich gefunden, das problem ist in der RSA_sign-Methode des client-Programms. Diese Methode signieren des hash-Ergebnis, um die digitale Signatur, die verwendet werden, in das SSL-Client-Verify-Nachricht. Der signaturvorgang wird berechnet, indem
CertFindCertificatePrivateKey/CryptCreateHash/CryptSetHashParam/CryptSignHash
APIs zu dieser Frage beschrieben. Der Fehler trat in die CryptCreateHash nennen, in denen die gesuchte hash-Verfahren SHA-384, aber die hCryptoProv abgerufen CertFindCertificatePrivateKey entsprach einer CSP (Microsoft Enhanced Cryptographic Provider v1.0) NICHT unterstützt SHA-2 hash-Methoden.Dies ist eine echte langweilige Beschreibung. Wenn Sie noch weiter Lesen, ich denke, Sie habe ein ähnliches problem auch. Lassen Sie mich Ihnen meine Lösung.
Meine erste Reaktion war, zum einstellen der SSL-Aushandlung param downgrade des hash-Algorithmus, SHA-1, aber ich nicht. Es scheint, SHA-2-hash ist obligatorisch für TLSv1.2. Auch wollte ich versuchen zu erreichen, der Zeichen-Vorgang durch die Verschlüsselung mit dem Zertifikat, private key, der wurde auch nicht. Crypto-API bietet KEINE Schnittstelle für Zertifikat, private key-Verschlüsselung (ich bin mir nicht sicher, aber ich habe es nicht gefunden.) Nach zwei Tagen resultless versuchen, ich fand diese Webseite: http://www.componentspace.com/Forums/Topic1578.aspx. Es ist wirklich wie das Licht am Ende des Tunnels. Das Zertifikat ist verbindlich mit einem CSP nicht unterstützt SHA-2, wenn wir können, wandeln Sie es in ein CSP unterstützt SHA-2, alles wird in Ordnung sein. Im Fall von broken link, ich fügen Sie die Konvertierungs-Methode hier:
Ich nur umgebaut .pfx Zertifikat-Datei als Webseite sagte; re-importiert das Zertifikat. Dann ist das problem gelöst.
Hoffe, das ist hilfreich. 🙂
InformationsquelleAutor GrepAll