Получить SSL в режиме сервера должен использовать сертификат с соответствующим закрытым ключом. ошибка в X509Certificate2 при использовании .cer вместо .pfx

Я использую файлы .cer и .key на пользовательском веб-сервере для проверки ssl с помощью SslStream.AuthenticateAsServerAsync(). процесс создания X509Certificate2 выглядит примерно так:

var bytes = File.ReadAllBytes(certificatePath);
using var publicKey = new X509Certificate2(bytes,default(string));


var privateKeyText = File.ReadAllText(privateKeyPath);
var privateKeyBlocks = privateKeyText.Split("-", StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim('\n')).ToArray();
var privateKeyBytes = Convert.FromBase64String(privateKeyBlocks[1]);

        
using var rsa = RSA.Create();

if (privateKeyBlocks[0] == "BEGIN PRIVATE KEY")
   {
      rsa.ImportPkcs8PrivateKey(privateKeyBytes, out _);
   }
else if (privateKeyBlocks[0] == "BEGIN RSA PRIVATE KEY")
   {
      rsa.ImportRSAPrivateKey(privateKeyBytes, out _);
   }

var keyPair = publicKey.CopyWithPrivateKey(rsa);
return new X509Certificate2(keyPair.Export(X509ContentType.Pfx));

При использовании .pfx все это нормально, но с помощью этого кода для замены файла .pfx (и его создания) файлами .cer и .key в SslStream.AuthenticateAsServerAsync() я получил эту ошибку:

System.Security.Authentication.AuthenticationException: The server mode SSL must use a certificate with the associated private key.

Другой способ, который я использую для этого:

 X509Certificate2 certWithKey = default;
 try
 {
   string keyPem = File.ReadAllText(keyFile);
   byte[] keyDer = UnPem(keyPem);
   using (X509Certificate2 certOnly = new X509Certificate2(cerFile))
   {
       using (RSA rsa = RSA.Create())
       {
           // For "BEGIN PRIVATE KEY"
           rsa.ImportPkcs8PrivateKey(keyDer, out _);
           var tmp = certOnly.CopyWithPrivateKey(rsa);
           certWithKey = new X509Certificate2(tmp.Export(X509ContentType.Pfx));
       }
   }
   Serilog.Log.ForContext("Path", cerFile).Information("Create certificate from {FileName} successfully.", Path.GetFileName(cerFile));
 }
 catch (Exception ex)
 {
    Logger.LogError(ex, "Error in create certificate from {Path}", cerFile);
 }
 return certWithKey;
 static byte[] UnPem(string pem)
 {
    // This is a shortcut that assumes valid PEM
    // -----BEGIN words-----\nbase64\n-----END words-----
    const string Dashes = "-----";
    int index0 = pem.IndexOf(Dashes);
    int index1 = pem.IndexOf('\n', index0 + Dashes.Length);
    int index2 = pem.IndexOf(Dashes, index1 + 1);
    return Convert.FromBase64String(pem.Substring(index1, index2 - index1));
}

Также в .net 5 используйте этот новый способ:

return X509Certificate2.CreateFromPemFile(certificatePath,privateKeyPath);

Но проблема не решена.

Все, что я хочу, это создать X509Certificate2 из файлов .cer и .key, а не из файла .pfx. Я не знаю, что и где проблема. Создание X509Certificate2 вызывает проблему, или я пропускаю некоторые другие вещи (например, при проверке sslstream). танки, чтобы помочь мне узнать проблему и лучший способ сделать это.


person Ali Qamsari    schedule 18.04.2021    source источник
comment
Вы терпите неудачу только в Windows? Если это так, то SslStream не поддерживает эфемерные закрытые ключи. Вам нужно будет экспортировать результат CreateFromPemFile как Pkcs12/Pfx и снова импортировать его, чтобы принять участие в некоторой магии PFX, от которой зависит SslStream.   -  person bartonjs    schedule 19.04.2021
comment
танки @bartonjs. ваше предложение помогло мне   -  person Ali Qamsari    schedule 20.04.2021


Ответы (1)


В баках bartonjs моя проблема решена следующим образом:

string pass = Guid.NewGuid().ToString();
var certificate = X509Certificate2.CreateFromPemFile(certificatePath, privateKeyPath);
return new X509Certificate2(certificate.Export(X509ContentType.Pfx, pass), pass);

Создайте в памяти сертификат типа .pfx из файла .cer со случайным паролем и используйте его вместо исходного сертификата.

person Ali Qamsari    schedule 19.04.2021