Pregunta

Estoy creando un sistema de distribución de certificados para realizar un seguimiento de los clientes y otras cosas.

Lo que ocurre es:

  • El cliente envía al servidor RSE
  • Server comprueba y signos certificado
  • Servidor envía el certificado al cliente Firmado
  • Cliente pone certificado firmado además de la clave privada en la tienda de Windows.

Así en el cliente esto sucede:

//Pseudo Server Object:
Server s = new Server();  

//Requested Certificate Name and things
X509Name name = new X509Name("CN=Client Cert, C=NL");  

//Key generation 2048bits
RsaKeyPairGenerator rkpg = new RsaKeyPairGenerator();
rkpg.Init(new KeyGenerationParameters(new SecureRandom(), 2048));
AsymmetricCipherKeyPair ackp = rkpg.GenerateKeyPair();  

//PKCS #10 Certificate Signing Request
Pkcs10CertificationRequest csr = new Pkcs10CertificationRequest("SHA1WITHRSA", name, ackp.Public, null, ackp.Private);  

//Make it a nice PEM thingie
StringBuilder sb = new StringBuilder();
PemWriter pemwrit = new PemWriter(new StringWriter(b));
pemwrit.WriteObject(csr);
pemwrit.Writer.Flush();
s.SendRequest(sb.ToSting());

Ok, así que voy a saltar serverside sólo confía en mí el servidor firma el certificado y lo envía de vuelta al cliente. Ahí es donde voy a recoger la acción.

PemReader pr = new PemReader(new StringReader(b.ToString()));
X509Certificate cert = (X509Certificate)pr.ReadObject();  

//So lets asume I saved the AsymmetricCipherKeyPair (ackp) from before
//I have now the certificate and my private key;

//first I make it a "Microsoft" x509cert.
//This however does not have a PrivateKey thats in the AsymmetricCipherKeyPair (ackp)
System.Security.Cryptography.X509Certificates.X509Certificate2 netcert = DotNetUtilities.ToX509Certificate(cert);

//So here comes the RSACryptoServerProvider:
System.Security.Cryptography.RSACryptoServiceProvider rcsp = new System.Security.Cryptography.RSACryptoServiceProvider();  

//And the privateKeyParameters
System.Security.Cryptography.RSAParameters parms = new System.Security.Cryptography.RSAParameters();  

//now I have to translate ackp.PrivateKey to parms;
RsaPrivateCrtKeyParameters BCKeyParms = ((RsaPrivateCrtKeyParameters)ackp1.Private);  

//D is the private exponent
parms.Modulus   = BCKeyParms.Modulus.ToByteArray();
parms.P         = BCKeyParms.P.ToByteArray();
parms.Q         = BCKeyParms.Q.ToByteArray();
parms.DP        = BCKeyParms.DP.ToByteArray();
parms.DQ        = BCKeyParms.DQ.ToByteArray();
parms.InverseQ  = BCKeyParms.QInv.ToByteArray();
parms.D         = BCKeyParms.Exponent.ToByteArray();
parms.Exponent  = BCKeyParms.PublicExponent.ToByteArray();  

//Now I should be able to import the RSAParameters into the RSACryptoServiceProvider
rcsp.ImportParameters(parms);  

//<em><b>not really</b></em> This breaks says "Bad Data" and not much more. I'll Post the 
//stacktrace at the end  

//I open up the windows cert store because thats where I want to save it.
//Add it and save it this works fine without the privkey.
X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.MaxAllowed);
store.Add(netcert);
store.Close();

Ahora usted está pensando probablemente debe haber algo va mal en el lado del servidor. Pues eso es lo que pensé también, pero cuando hice un archivo PFX de este cert e importados a mano funcionó bien ....

De alguna manera hay una diference bewteen un PrivateKey .NET RSA y RSA PrivateKey BouncyCastle y no puedo poner mi dedo en él.

Es probable que sugieren que importar el PFX y luego obtener la clave privada de ella a través de la X509Store. Lo intenté. : S y fracasó. Tan pronto como trato de ExportParameters(true) los verdaderos soportes para la inclusión de privateparameters. Se dice "Clave no válida para su uso en estado.". Véase, por excepción completa al final.

Espero que algunos de ustedes han matado a este cerdo antes o podría ser capaz de ayudarme.

***Exceptions:***

System.Security.Cryptography.CryptographicException was unhandled
  Message="Key not valid for use in specified state.\r\n"
  Source="mscorlib"
  StackTrace:
       at System.Security.Cryptography.CryptographicException.ThrowCryptogaphicException(Int32 hr)
       at System.Security.Cryptography.Utils._ExportKey(SafeKeyHandle hKey, Int32 blobType, Object cspObject)
       at System.Security.Cryptography.RSACryptoServiceProvider.ExportParameters(Boolean includePrivateParameters)
  InnerException: 

***And the other one:***

System.Security.Cryptography.CryptographicException was unhandled
  Message="Bad Data.\r\n"
  Source="mscorlib"
  StackTrace:
       at System.Security.Cryptography.CryptographicException.ThrowCryptogaphicException(Int32 hr)
       at System.Security.Cryptography.Utils._ImportKey(SafeProvHandle hCSP, Int32 keyNumber, CspProviderFlags flags, Object cspObject, SafeKeyHandle& hKey)
       at System.Security.Cryptography.RSACryptoServiceProvider.ImportParameters(RSAParameters parameters)
  InnerException: 
¿Fue útil?

Solución

La respuesta (de nombre de usuario) apunta a la dirección correcta:. relleno

última versión de hinchables-castillo de Git tiene el siguiente código:

public static RSAParameters ToRSAParameters(RsaPrivateCrtKeyParameters privKey)
{
   RSAParameters rp = new RSAParameters();
   rp.Modulus = privKey.Modulus.ToByteArrayUnsigned();
   rp.Exponent = privKey.PublicExponent.ToByteArrayUnsigned();
   rp.P = privKey.P.ToByteArrayUnsigned();
   rp.Q = privKey.Q.ToByteArrayUnsigned();
   rp.D = ConvertRSAParametersField(privKey.Exponent, rp.Modulus.Length);
   rp.DP = ConvertRSAParametersField(privKey.DP, rp.P.Length);
   rp.DQ = ConvertRSAParametersField(privKey.DQ, rp.Q.Length);
   rp.InverseQ = ConvertRSAParametersField(privKey.QInv, rp.Q.Length);
   return rp;
}

private static byte[] ConvertRSAParametersField(BigInteger n, int size)
{
   byte[] bs = n.ToByteArrayUnsigned();
   if (bs.Length == size)
      return bs;
   if (bs.Length > size)
      throw new ArgumentException("Specified size too small", "size");
   byte[] padded = new byte[size];
   Array.Copy(bs, 0, padded, size - bs.Length, bs.Length);
   return padded;
}

NB:. Este código en no en la versión Nuget (2011) del castillo hinchable, o en la mayoría de los ejemplos de código RSA fueron parámetros se copian simplemente

Este código es diferente del código se puede ver en cualquier otro lugar que básicamente copiar / pegar los parámetros clave, y no realiza el paso de relleno adicional.

Otros consejos

Para su información, he añadido esta funcionalidad a la clase Org.BouncyCastle.Security.DotNetUtilities; será en versión 1.6, debido pronto.

Lo encontré!

o al menos parte de ella:)

En cuanto a la PrivateKey.ExportToParameters(true) Aún doens't trabajo, pero esto tiene algo TODO con el hecho de que la clave era de 2048 bits. Porque cuando lo cambié a 1024bit lo hizo el trabajo. Así que si alguien descubre por qué Manténganme.

Así que aquí vamos de nuevo.

//BouncyCastle's Key objects
RsaPrivateCrtKeyParameters rpckp = ((RsaPrivateCrtKeyParameters)ackp.Private);

//.NET RSA Key objects
System.Security.Cryptography.RSACryptoServiceProvider rcsp = new System.Security.Cryptography.RSACryptoServiceProvider();
System.Security.Cryptography.RSAParameters parms = new System.Security.Cryptography.RSAParameters();

//So the thing changed is offcourse the ToByteArrayUnsigned() instead of
//ToByteArray()
parms.Modulus   = rpckp.Modulus.ToByteArrayUnsigned();
parms.P         = rpckp.P.ToByteArrayUnsigned();
parms.Q         = rpckp.Q.ToByteArrayUnsigned();
parms.DP        = rpckp.DP.ToByteArrayUnsigned();
parms.DQ        = rpckp.DQ.ToByteArrayUnsigned();
parms.InverseQ  = rpckp.QInv.ToByteArrayUnsigned();
parms.D         = rpckp.Exponent.ToByteArrayUnsigned();
parms.Exponent  = rpckp.PublicExponent.ToByteArrayUnsigned();

//So now this now appears to work.
rcsp.ImportParameters(parms);

Así que ahora puedo agregar el certificado completa a mi tienda :)

Creo que he encontrado la solución a este problema. No tiene nada que ver con el por clave, sino más bien con el objeto X509Certificate2 que debe ser creado con la bandera X509KeyStorageFlags.Exportable.

En este caso, su X509Certificate2 fue creado por este método: System.Security.Cryptography.X509Certificates.X509Certificate2 netcert = DotNetUtilities.ToX509Certificate(cert);

Así que asegúrese de que pase la bandera exportable en el constructor de la X509Certificate2 en ese método. Yo mi situación que tenía que firmar unos datos con una clave privada situada en un archivo PFX por lo que tuvo que escribir esto:

X509KeyStorageFlags flags = X509KeyStorageFlags.Exportable;
X509Certificate2 cert = new X509Certificate2("my.pfx", "somepass", flags);

Ahora puedo hacer
RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)cert.PrivateKey;
RSAParameters rsaParam = rsa.ExportParameters(true);

HTH,

Stefan

Ninguna de las soluciones trabajó para mí. Pero me he dado cuenta de que la excepción siempre se produce cuando una de las siguientes matrices:

parms.Modulus   = rpckp.Modulus.ToByteArrayUnsigned();
parms.P         = rpckp.P.ToByteArrayUnsigned();
parms.Q         = rpckp.Q.ToByteArrayUnsigned();
parms.DP        = rpckp.DP.ToByteArrayUnsigned();
parms.DQ        = rpckp.DQ.ToByteArrayUnsigned();
parms.InverseQ  = rpckp.QInv.ToByteArrayUnsigned();
parms.D         = rpckp.Exponent.ToByteArrayUnsigned();
parms.Exponent  = rpckp.PublicExponent.ToByteArrayUnsigned();

tiene un tamaño diferente a su vecino:

DP, DQ, InverseQ, P, Q

o de tamaño doble:

D, Modulus

Para cada uno de estos dos grupos He calculado la longitud max y añadido ceros adicionales al comienzo de cada matriz para que sean de la misma longitud (el mismo para cada grupo). Esto funciona, supongo que los controles ImportParameters que son de la misma longitud (por desgracia no tengo acceso al código ImportParameters, parece que se llama a algunos biblioteca nativa).

Estoy usando BouncyCastle.Crypto.dll ver 1.7

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top