Unable to decode certificate at client new X509Certificate2()

孤街醉人 提交于 2019-12-10 21:15:54

问题


I'm using this little class which returns me a pfx file in byte array.

Server side:

byte[] serverCertificatebyte;
var date = new DateTime(DateTime.Today.Year, DateTime.Today.Month, DateTime.Today.Day);
serverCertificatebyte = Certificate.CreateSelfSignCertificatePfx("CN=RustBuster" + RandomString(5),
    date,
    date.AddDays(7));

Then I send It to the client (length: 1654):

tcpClient.GetStream().Write(serverCertificatebyte , 0, serverCertificatebyte .Length);

Once the client read It, I would like to convert It to a certificate class: (Length is also 1654 here)

I try to do a new X509Certificate2(data); and I get the error down below. This works on server side. What's the matter?

I also tried It with new X509Certificate2(data, string.Empty); and got the same error

Error System.Security.Cryptography.CryptographicException: Unable to decode certificate. ---> System.Security.Cryptography.CryptographicException: Input data cannot be coded as a valid certificate. ---> System.ArgumentOutOfRangeException: Cannot be negative.

Parameter name: length

at System.String.Substring (Int32 startIndex, Int32 length) [0x00000] in :0

at Mono.Security.X509.X509Certificate.PEM (System.String type, System.Byte[] data) [0x00000] in :0

at Mono.Security.X509.X509Certificate..ctor (System.Byte[] data) [0x00000] in :0


回答1:


There is a bug in Mono when using X509Certificate2 constructor to load PKCS#12 with empty password. A patch has been submitted to fix this issue but it is (probably) not released in your version of mono.

Try to save the bytes to a file and then use new X509Certificate2(filepath, String.Empty) or new X509Certificate2(filepath, null) or create pfx with some default non-empty password.




回答2:


Long thoughts and help requests finally lead me to a solution.

The following way or examples to a persistent connections that I had DID NOT WORK AT ALL.

At the server side you first must get the length of the byte you would like to send, and write It to the stream. This most likely going to be a byte having the length of 4.

byte[] intBytes = BitConverter.GetBytes(serverCertificatebyte.Length);
Array.Reverse(intBytes);

On the client side, read that byte, and convert It to an int:

byte[] length = new byte[4];
int red = 0;
while (true)
{
    red = stream.Read(length, 0, length.Length);
    if (red != 0)
    {
        break;
    }
}
if (BitConverter.IsLittleEndian)
{
    Array.Reverse(length);
}
int i = (BitConverter.ToInt32(length, 0)); // The length of the byte that the server sent
// By this time your server already sent the byte (Right after you sent the length) tcpClient.GetStream().Write(byte, 0, byte.Length);
byte[] data = ByteReader(i);

This method is going to read the byte that you send from the server until It's possible

internal byte[] ByteReader(int length)
{
    using (NetworkStream stream = client.GetStream())
    {
        byte[] data = new byte[length];
        using (MemoryStream ms = new MemoryStream())
        {
            int numBytesRead;
            int numBytesReadsofar = 0;
            while (true)
            {
                numBytesRead = stream.Read(data, 0, data.Length);
                numBytesReadsofar += numBytesRead;
                ms.Write(data, 0, numBytesRead);
                if (numBytesReadsofar == length)
                {
                    break;
                }
            }
            return ms.ToArray();
        }
    }
}

This solution seems to be working pretty well unlike the other examples that were provided on the microsoft documentation page. I hope this will help others too.



来源:https://stackoverflow.com/questions/34503063/unable-to-decode-certificate-at-client-new-x509certificate2

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!