X509Certificate Constructor-Ausnahme

73
//cert is an EF Entity and 
//    cert.CertificatePKCS12 is a byte[] with the certificate.

var certificate = new X509Certificate(cert.CertificatePKCS12, "SomePassword");

Beim Laden eines Zertifikats aus unserer Datenbank auf unserem Staging-Server (Windows 2008 R2 / IIS7.5) wird folgende Ausnahme angezeigt:

System.Security.Cryptography.CryptographicException: An internal error occurred.

   at System.Security.Cryptography.CryptographicException.ThrowCryptographicException(Int32 hr)
   at System.Security.Cryptography.X509Certificates.X509Utils._LoadCertFromBlob(Byte[] rawData, IntPtr password, UInt32 dwFlags, Boolean persistKeySet, SafeCertContextHandle& pCertCtx)
   at System.Security.Cryptography.X509Certificates.X509Certificate.LoadCertificateFromBlob(Byte[] rawData, Object password, X509KeyStorageFlags keyStorageFlags)

HINWEIS: Dieses Problem tritt nicht lokal auf (Windows 7 / Casini).

Jeder Einblick wird sehr geschätzt.

lukiffer
quelle
1
Ich nehme an, dass die Ursache des Problems in den byte[] Daten liegt, die in cert.CertificatePKCS12. Ohne die Daten kann man nur den Grund der Ausnahme "Ein interner Fehler ist aufgetreten" erraten. Mein Vorschlag ist also, dass Sie das Testzertifikat erstellen, das in Ihrer Umgebung verwendet werden kann, um das Problem zu reproduzieren, es in der Datei speichern und den Link und das Kennwort (wie "SomePassword") zum Dekodieren des Zertifikats angeben. Nach Prüfung der Daten hat man viel mehr Chancen, die Resonanz zu finden und eine Lösung für Ihr Problem vorzuschlagen.
Oleg
Vielen Dank für die Antwort @Oleg - wenn das Byte-Array schlecht wäre, würde es nicht sowohl unter Win7 als auch unter Win2k8 fehlerhaft sein? Wenn das Byte-Array in eine Datei geschrieben wird, wird es korrekt importiert.
Lukiffer
@lukiffer: Ich meine keinen Fehler, sondern kombiniere einige Eigenschaften des Zertifikats, des Schlüssels und so weiter. Man muss also das Problem analysieren . Um die Ergebnisse reproduzieren oder analysieren zu können, muss die PFX-Datei vorhanden sein, die Sie als Byte-Array verwenden cert.CertificatePKCS12.
Oleg
@oleg - Welche Eigenschaften würden dazu führen, dass es auf einem Betriebssystem und nicht auf einem anderen fehlschlägt? Aus offensichtlichen Sicherheitsgründen können wir die Zertifikate nicht selbst freigeben.
Lukiffer

Antworten:

126

Es stellt sich heraus, dass in der IIS-Anwendungspoolkonfiguration (Anwendungspools> Erweiterte Einstellungen) eine Einstellung zum Laden des Benutzerprofils für den Benutzer der Anwendungspoolidentität vorhanden ist. Bei false sind die Schlüsselcontainer nicht zugänglich.

Stellen Sie einfach die Load User ProfileOption als einTrue

App Pool-> Erweiterte Einstellungen Bildschirm

lukiffer
quelle
Nur eine Anmerkung, dass dies für IIS7 ist; In IIS6 gibt es meines Erachtens keine Option zum Laden des Benutzerprofils.
Randy unterstützt Monica
2
Ich versuche dies in Azure und weiß nicht, ob ich die Option "Benutzerprofil laden" ändern kann. Irgendwelche Vorschläge ... Ich bin noch ziemlich neu in der Welt der Zertifikate ...
Dan B
1
@DanB für Azure Fügen Sie die Anwendungseinstellung hinzu: WEBSITE_LOAD_USER_PROFILE = 1
emp
61

Wenn Sie in Visual Studio / Cassini ausgeführt werden, greift es höchstwahrscheinlich auf Ihren Benutzerzertifikatsspeicher zu, obwohl Sie ihn aus Bytes laden. Könnten Sie dies bitte versuchen und sehen, ob es Ihr Problem löst:

var certificate = new X509Certificate(
    cert.CertificatePKCS12, "SomePassword", X509KeyStorageFlags.MachineKeySet);

Dies führt dazu, dass IIS (das als ASP.NET-Benutzer ausgeführt wird, der wahrscheinlich keinen Zugriff auf einen Benutzerspeicher hat) den Computerspeicher verwendet.

Auf dieser Seite wird der Konstruktor ausführlicher erläutert, und auf dieser Seite wird die X509KeyStorageFlagsAufzählung erläutert .

Bearbeiten: Basierend auf dem zweiten Link von cyphr scheint es eine gute Idee zu sein (wenn die vorherige Lösung nicht funktioniert), einige der FlagsAttributeAufzählungswerte wie folgt zu kombinieren :

var certificate = new X509Certificate(
    cert.CertificatePKCS12, "SomePassword",
    X509KeyStorageFlags.MachineKeySet
    | X509KeyStorageFlags.PersistKeySet
    | X509KeyStorageFlags.Exportable);

Wenn Sie Zugriff haben, können Sie außerdem versuchen, die Einstellung für den Anwendungspool so zu ändern, dass LocalService verwendet wird (und anschließend den AppPool neu starten). Dies kann Ihre Berechtigungen auf ein angemessenes Niveau erhöhen, wenn dies das Problem ist.

Schließlich können Sie File.WriteAllBytesden CertificatePKCS12Inhalt in eine pfx-Datei schreiben und prüfen, ob Sie ihn manuell über die Zertifikatkonsole unter MMC importieren können (Sie können ihn nach erfolgreichem Import löschen; dies dient nur zum Testen). Es kann sein, dass Ihre Daten munged werden oder das Passwort falsch ist.

Chris Benard
quelle
Vielen Dank für die Antwort, obwohl es die gleiche Ausnahme noch zu werfen ist nur die nach dem Hinzufügen X509KeyStorageFlags.MachineKeySetFlagge, sowie wenn alle drei das Hinzufügen MachineKeySet, PersistKeySetund ExportableFlaggen.
lukiffer
1
Können Sie die Identität Ihres AppPools in LocalService ändern?
Chris Benard
Verwenden Sie diese Option auch, File.WriteAllBytesum den CertificatePKCS12Inhalt in eine pfx-Datei zu schreiben und zu prüfen, ob Sie ihn manuell über die Zertifikatkonsole unter MMC importieren können (Sie können ihn nach erfolgreichem Import löschen; dies dient nur zum Testen). Es kann sein, dass Ihre Daten munged werden oder das Passwort falsch ist.
Chris Benard
1
OK. Ich habe die Antwort aktualisiert, um sie einzuschließen, falls eine dieser Arbeiten funktioniert. Ich versuche die +50 zu verdienen. :)
Chris Benard
1
Beachten Sie, dass Sie, wenn Sie SignTool.exevon Ihrem ASP.NET-Projekt aus aufrufen möchten, weiterhin 'LoadUserProfile' für das aktivieren müssen Application Pool. Andernfalls SignTool.exeAn internal error occurred
schlägt der
32

Verwenden Sie diesen Code:

certificate = new X509Certificate2(System.IO.File.ReadAllBytes(p12File)
                                   , p12FilePassword
                                   , X509KeyStorageFlags.MachineKeySet |
                                     X509KeyStorageFlags.PersistKeySet | 
                                     X509KeyStorageFlags.Exportable);
Francisco
quelle
1
Nur das letzte Bit mit den 3 oder Anweisungen hinzuzufügen, brachte meine Sachen zum Laufen. Guter Code, der immer noch relevant ist.
Jobokai
1
Arbeitete für mich beim Versuch, ein Zertifikat als eingebettete Ressource in IIS zu laden.
Robin van der Knaap
Dies war das Problem für mich bei der Verwendung von spire.pdf
HaBo
8

Ich hatte Probleme mit Windows 2012 Server R2, wo meine Anwendung keine Zertifikate für einen PFX auf die Festplatte laden konnte. Es würde gut funktionieren, wenn meine App als Administrator ausgeführt würde, und die Ausnahme lautete "Zugriff verweigert", sodass es sich um ein Berechtigungsproblem handeln musste. Ich habe einige der oben genannten Ratschläge ausprobiert, aber ich hatte immer noch das Problem. Ich fand, dass die Angabe der folgenden Flags als dritter Parameter des Zertifikatskonstruktors den Trick für mich tat:

 X509KeyStorageFlags.UserKeySet | 
 X509KeyStorageFlags.PersistKeySet | 
 X509KeyStorageFlags.Exportable
Michael Balloni
quelle
2

Um Ihr Problem wirklich lösen zu können und nicht nur zu erraten, was es sein kann, muss man in der Lage sein , Ihr Problem zu reproduzieren . Wenn Sie keine Test-PFX-Datei mit demselben Problem bereitstellen können, müssen Sie das Problem selbst untersuchen. Die erste wichtige Frage lautet: Liegt der Ursprung der Ausnahme "Ein interner Fehler ist aufgetreten" im privaten Schlüsselteil des PKCS12 oder im öffentlichen Teil des Zertifikats selbst?

Daher würde ich Ihnen empfehlen, dasselbe Experiment mit demselben Zertifikat zu wiederholen, das ohne privaten Schlüssel exportiert wurde (wie die .CER-Datei):

var certificate = new X509Certificate(cert.CertificateCER);

oder

var certificate = new X509Certificate.CreateFromCertFile("My.cer");

Es kann hilfreich sein, zu überprüfen, ob der Ursprung Ihres Problems der private Schlüssel oder einige Eigenschaften des Zertifikats sind.

Wenn Sie Probleme mit der CER-Datei haben, können Sie den Link zur Datei sicher veröffentlichen, da er nur öffentliche Informationen enthält. Alternativ können Sie zumindest ausführen

CertUtil.exe -dump -v "My.cer"

oder

CertUtil.exe -dump -v -privatekey -p SomePassword "My.pfx"

(Sie können auch einige andere Optionen verwenden) und einige Teile der Ausgabe veröffentlichen (z. B. Eigenschaften des privaten Schlüssels ohne das PRIVATEKEYBLOB selbst).

Oleg
quelle
1

Sie müssen ein CER-Zertifikat in den Keystore Ihres lokalen Computers importieren. Sie müssen Ihr .p12-Zertifikat nicht importieren. Verwenden Sie stattdessen das zweite von Apple für Ihr Konto ausgestellte Zertifikat. Ich denke, es muss ein gültiges Zertifikatspaar sein (eines im Dateisystem, das zweite im Keystore). Sie müssen natürlich alle 3 Flags in dll setzen.

PanRycho
quelle
0

In einer Anwendung, in der IIS 10 ausgeführt wird, konnte ich den Fehler beim Verweigern des Zugriffs beheben, indem ich die LocalSystem-Identität für den App-Pool mit dem folgenden Code verwendete:

new X509Certificate2(certificateBinaryData, "password"
                               , X509KeyStorageFlags.MachineKeySet |
                                 X509KeyStorageFlags.PersistKeySet);

Das Aktivieren des Ladeprofils für Benutzer hat bei mir nicht funktioniert, und obwohl es viele Vorschläge dazu gab, wurde nicht angegeben, dass die Einstellung für "Benutzerprofil laden" auf "True" nur für Benutzerkonten funktioniert und nicht:

  1. ApplicationPoolIdentity
  2. Netzwerkdienst
Thabiso Mofokeng
quelle
0

Der folgende Code hilft Ihnen dabei, mithilfe der Hüpfburgbibliothek einen Algorithmus zu generieren:

private static ECDsa GetEllipticCurveAlgorithm(string privateKey)
{
    var keyParams = (ECPrivateKeyParameters)PrivateKeyFactory
        .CreateKey(Convert.FromBase64String(privateKey));

    var normalizedECPoint = keyParams.Parameters.G.Multiply(keyParams.D).Normalize();

    return ECDsa.Create(new ECParameters
    {
        Curve = ECCurve.CreateFromValue(keyParams.PublicKeyParamSet.Id),
        D = keyParams.D.ToByteArrayUnsigned(),
        Q =
    {
        X = normalizedECPoint.XCoord.GetEncoded(),
        Y = normalizedECPoint.YCoord.GetEncoded()
    }
    });
}

und generieren Sie das Token folgendermaßen:

var signatureAlgorithm = GetEllipticCurveAlgorithm(privateKey);

        ECDsaSecurityKey eCDsaSecurityKey = new ECDsaSecurityKey(signatureAlgorithm)
        {
            KeyId = settings.Apple.KeyId
        };

        var handler = new JwtSecurityTokenHandler();   
        var token = handler.CreateJwtSecurityToken(
            issuer: iss,
            audience: AUD,
            subject: new ClaimsIdentity(new List<Claim> { new Claim("sub", sub) }),
            expires: DateTime.UtcNow.AddMinutes(5), 
            issuedAt: DateTime.UtcNow,
            notBefore: DateTime.UtcNow,
            signingCredentials: new SigningCredentials(eCDsaSecurityKey, SecurityAlgorithms.EcdsaSha256));
Shah Zaiƞ
quelle