2013-05-07 3 views
9

Ich muss generierte Zertifikate mit privaten Schlüsseln zu und von Bytearrays exportieren und importieren, und ich habe keine Probleme, wenn ich .NET Framework 4.0 verwende und 4.5. Ich erzeuge selbstsignierte Zertifikate mit der Bibliothek BouncyCastle und konvertiere sie dann in das .net-Format (X509Certificate2-Objekt). Leider kann ich mit dem Upgrade auf ein neuestes Framework keine privaten Schlüssel exportieren. Hier ist der Code:Kann generiertes Zertifikat mit privatem Schlüssel nicht in Byte-Array in .net 4.0/4.5 exportieren.

using System; 
using System.Diagnostics; 
using System.Security.Cryptography; 
using System.Security.Cryptography.X509Certificates; 
using Org.BouncyCastle.Asn1.X509; 
using Org.BouncyCastle.Crypto; 
using Org.BouncyCastle.Crypto.Generators; 
using Org.BouncyCastle.Crypto.Parameters; 
using Org.BouncyCastle.Crypto.Prng; 
using Org.BouncyCastle.Math; 
using Org.BouncyCastle.Security; 
using Org.BouncyCastle.X509; 

namespace X509CertificateExport 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      var certificate = Generate(); 
      var exported = certificate.Export(X509ContentType.Pfx); 
      var imported = new X509Certificate2(exported, (string)null, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet); 

      Console.WriteLine("Certificate has private key: " + imported.HasPrivateKey); 
      Console.ReadKey(); 
     } 

     public static X509Certificate2 Generate() 
     { 
      var keyPairGenerator = new RsaKeyPairGenerator(); 
      var secureRandom = new SecureRandom(new CryptoApiRandomGenerator()); 
      keyPairGenerator.Init(new KeyGenerationParameters(secureRandom, 1024)); 
      var keyPair = keyPairGenerator.GenerateKeyPair(); 
      var publicKey = keyPair.Public; 
      var privateKey = (RsaPrivateCrtKeyParameters)keyPair.Private; 

      var generator = new X509V3CertificateGenerator(); 
      generator.SetSerialNumber(BigInteger.ProbablePrime(120, new Random())); 
      generator.SetSubjectDN(new X509Name("CN=Test")); 
      generator.SetIssuerDN(new X509Name("CN=Test")); 
      generator.SetNotAfter(DateTime.Now + new TimeSpan(10, 10, 10, 10)); 
      generator.SetNotBefore(DateTime.Now.Subtract(new TimeSpan(7, 0, 0, 0))); 
      generator.SetSignatureAlgorithm("MD5WithRSA"); 
      generator.SetPublicKey(publicKey); 

      var newCert = generator.Generate(privateKey); 
      var dotNetPrivateKey = ToDotNetKey(privateKey); 
      var dotNetCert = new X509Certificate2(DotNetUtilities.ToX509Certificate(newCert)); 
      dotNetCert.PrivateKey = dotNetPrivateKey; 

      return dotNetCert; 
     } 

     public static AsymmetricAlgorithm ToDotNetKey(RsaPrivateCrtKeyParameters privateKey) 
     { 
      var rsaProvider = new RSACryptoServiceProvider(); 
      var parameters = new RSAParameters 
      { 
       Modulus = privateKey.Modulus.ToByteArrayUnsigned(), 
       P = privateKey.P.ToByteArrayUnsigned(), 
       Q = privateKey.Q.ToByteArrayUnsigned(), 
       DP = privateKey.DP.ToByteArrayUnsigned(), 
       DQ = privateKey.DQ.ToByteArrayUnsigned(), 
       InverseQ = privateKey.QInv.ToByteArrayUnsigned(), 
       D = privateKey.Exponent.ToByteArrayUnsigned(), 
       Exponent = privateKey.PublicExponent.ToByteArrayUnsigned() 
      }; 

      rsaProvider.ImportParameters(parameters); 
      return rsaProvider; 
     } 
    } 
} 

Nach einem genaueren Blick auf die generierte Zertifikat habe ich bemerkt, dass PrivateKey.CspKeyContainerInfo.Exportable Flag für .NET Framework 3.5 ist wahr, aber für eine spätere Versionen wirft:

'Exportable' threw an exception of type 
'System.Security.Cryptography.CryptographicException'/Key does not exist 

Der einzige Unterschied, den ich sehe, ist in PrivateKey.CspKeyContainerInfo.m_parameters.Flags: .NET 3.5 - 'NoFlags'; .NET 4.5 - 'CreateEphemeralKey'. Dokumentation besagt, dass CreateEphemeralKey einen temporären Schlüssel erstellt, der freigegeben wird, wenn das zugeordnete RSA-Objekt geschlossen wird. Es wurde mit 4.0 Framework eingeführt und existierte vorher nicht. Ich habe versucht, dieses Flag zu beseitigen, indem ich explizit CspParameters erstelle:

aber ohne Glück. 'CreateEphemeralKey' wird trotzdem hinzugefügt, also bekomme ich als Ergebnis UseMachineKeyStore | CreateEphemeralKey Flags und ich sehe nicht, wie ich es entfernen kann. Gibt es eine Möglichkeit, wie ich diese Flagge ignorieren und Zertifikat mit privatem Schlüssel normalerweise exportieren kann?

+0

möglich Duplikat [Einfügen-Zertifikat (mit privatekey) in Root, Localmachine Zertifikatspeicher nicht in .NET 4] (http://stackoverflow.com/questions/3625624/inserting-certificate-with-privatekey-in -root-localmachine-zertifikat-store) – albertjan

Antwort

12

Ich habe nicht bemerkt, dass CspKeyContainerInfo.CspParameters.KeyContainerName nach Schlüsselerstellung in .NET 4.0 und .NET 4.5 leer ist, aber in .NET 3.5 automatisch generiert wurde. Ich habe einen eindeutigen Namen für Container festgelegt und kann jetzt einen privaten Schlüssel exportieren.

public static AsymmetricAlgorithm ToDotNetKey(RsaPrivateCrtKeyParameters privateKey) 
{ 
    var cspParams = new CspParameters 
    { 
      KeyContainerName = Guid.NewGuid().ToString(), 
      KeyNumber = (int)KeyNumber.Exchange, 
      Flags = CspProviderFlags.UseMachineKeyStore 
    }; 

    var rsaProvider = new RSACryptoServiceProvider(cspParams); 
    // ... 
+0

Du bist __the__ man! Vielen Dank! – albertjan

+0

Das ist ein cooler @ Benutzername, Benutzername. –

+0

Diese "Fix" behebt auch den Fehler: SSL-Zertifikat hinzufügen fehlgeschlagen, Fehler: 1312 Eine angegebene Anmeldesitzung existiert nicht. Möglicherweise wurde es bereits beendet. – RcMan

Verwandte Themen