【问题标题】:Unable to decode certificate at client new X509Certificate2()无法在客户端新 X509Certificate2() 处解码证书
【发布时间】:2016-04-02 20:47:09
【问题描述】:

我正在使用这个little class,它返回一个字节数组中的 pfx 文件。

服务器端:

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));

然后我将它发送给客户端(长度:1654):

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

一旦客户阅读了它,我想将它转换为证书类: (这里长度也是1654)

我尝试做一个新的 X509Certificate2(data);我在下面得到错误。这适用于服务器端。怎么了?

我也试过 new X509Certificate2(data, string.Empty);并得到同样的错误

错误 System.Security.Cryptography.CryptographicException:无法解码证书。 ---> System.Security.Cryptography.CryptographicException:输入数据无法编码为有效证书。 ---> System.ArgumentOutOfRangeException: 不能为负数。

参数名称:长度

在 System.String.Substring (Int32 startIndex, Int32 长度) [0x00000] in :0

在 Mono.Security.X509.X509Certificate.PEM(System.String 类型,System.Byte[] 数据)[0x00000] in :0

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

【问题讨论】:

  • 您正在使用 Mono。它不是黑盒,所以尝试介入。我记得 X509Certificate2 类中有一个错误。不完全确定它是什么,但我认为它与从文件读取 pfx 与从字节 [] 读取有关。尝试将字节保存到文件中,然后使用new X509Certificate2(filepath, String.Empty)new X509Certificate2(filepath, null)
  • 等等。你是说我应该把字节变成一个文件然后读取它吗?
  • 是的。将 byte[] 写入文件,然后在 X509Certificate2 中使用该文件。
  • 好的。我希望这行得通。很快就会告诉结果。文件名应该是什么? .pfx?
  • X509Certificate2 类文件的扩展名无关紧要。但通常扩展名是 .p12 或 .pfx。

标签: c# ssl x509certificate2


【解决方案1】:

长时间的思考和帮助请求最终让我找到了解决方案。

以下方式或示例对我根本不起作用的持久连接。

在服务器端,您首先必须获取要发送的字节长度,并将其写入流中。这很可能是一个长度为 4 的字节。

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

在客户端,读取该字节,并将其转换为 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);

此方法将读取您从服务器发送的字节,直到有可能

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();
        }
    }
}

与 microsoft 文档页面上提供的其他示例不同,此解决方案似乎运行良好。我希望这对其他人也有帮助。

【讨论】:

    【解决方案2】:

    在使用 X509Certificate2 构造函数以空密码加载 PKCS#12 时,Mono 中存在错误。已提交 patch 以解决此问题,但它(可能)未在您的单声道版本中发布。

    尝试将字节保存到文件中,然后使用new X509Certificate2(filepath, String.Empty)new X509Certificate2(filepath, null) 或使用一些默认的非空密码创建pfx。

    【讨论】:

    • 我会使用默认的非空密码。
    • 不。我已经知道了,正如我上面提到的..“我也用 new X509Certificate2(data, string.Empty); 尝试了它,得到了同样的错误”这是一个 PFX 字节而不是 pkcs
    • @DreTaX pfx 是恕我直言 PKCS#12。您尝试在构造函数中加载字节 [] 而不是文件名。它的实施方式不同。如果您想在 X509Certificate2 的构造函数中使用 byte[],则使用非空密码创建 PFX,它应该可以工作。
    • 嗯。但是提供密码会加密数据。密码不会提供对私钥的访问权限吗?顺便说一句:db.tt/KzjxiQ4t
    • 好吧,我尝试在服务器端输入密码,然后在客户端使用它来访问它,但我仍然得到同样的错误。这件事在我脑海中浮现。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-14
    • 2017-02-03
    相关资源
    最近更新 更多