Как реализовать MTL между клиентом и сервером в C# с помощью Bouncy Castle?C#

Место общения программистов C#
Ответить Пред. темаСлед. тема
Anonymous
 Как реализовать MTL между клиентом и сервером в C# с помощью Bouncy Castle?

Сообщение Anonymous »

Я работаю над реализацией взаимных TLS (MTLS) в приложении C#, где: < /p>
Сервер управления ключами (KMS) генерирует сертификат корневого CA.
Знаки KMS Сертификат клиента для NMS (система управления сетью).
Клиент NMS представит свой подписанный сертификат при подключении к серверу KMS через TLS.
Сервер KMS будет проверять сертификат клиента, чтобы убедиться, что он был выпущен Корнем КМС КНЕЙ, прежде чем разрешить общение.
Я хотел бы достичь этого, используя библиотеку Bouncy Castle в C#. < /p>
Мой прогресс:
Я могу генерировать корень Сертификат CA и подпишите сертификат клиента, используя Bouncy Castle.
Я хочу:
Использовать сгенерированные сертификаты для сервера и клиента.
Проверьте сертификат клиента на стороне сервера во время рукопожатия TLS.
установить безопасную связь после успешной проверки.
Что мне нужна с помощью:
Как я могу правильно настроить сервер (sslstream) для проверки сертификата клиента во время рукопожатия?
Как Настроить ли я клиент для представления своего сертификата при установлении соединения TLS?
Можете ли вы привести полный пример реализаций сервера и клиентов для этого варианта использования?
Примечания:
Я хочу Используйте Bouncy Castle для создания и проверки сертификата.
Сервер и клиент общаются через TCP.
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.X509;
using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.OpenSsl;
using System;
using System.IO;
using Org.BouncyCastle.Crypto.Operators;
using System.Configuration;
using System.Net.Security;
using System.Net.Sockets;
using System.Security.Cryptography.X509Certificates;
using System.Net;

namespace CertificateGeneration
{
public class NmsCertificateGenerator
{
public static void GenerateCertificate(string kmsKeysPath, string nmsCertificatesPath)
{
// Generate and save KMS certificate and key
GenerateAndSaveKmsCertificate(kmsKeysPath);

// Generate and save NMS certificate using KMS keys
GenerateAndSaveNmsCertificate(kmsKeysPath, nmsCertificatesPath);

Console.WriteLine("Certificate and key generation completed.");
}

private static void GenerateAndSaveKmsCertificate(string kmsKeysPath)
{
var keyPair = GenerateRsaKeyPair(2048);
var cert = GenerateSelfSignedCertificate(keyPair, "CN=127.0.0.1");

// Save private key and certificate in PEM format
File.WriteAllText(Path.Combine(kmsKeysPath, "kms_private_key.pem"), ExportPrivateKeyToPem(keyPair));
File.WriteAllText(Path.Combine(kmsKeysPath, "kms_certificate.pem"), ExportCertificateToPem(cert));

// Export the public key from the KMS certificate
File.WriteAllText(Path.Combine(kmsKeysPath, "kms_public_key.pem"), ExportPublicKeyToPem(keyPair));

Console.WriteLine("KMS Certificate and Private Key saved successfully.");
}

private static void GenerateAndSaveNmsCertificate(string kmsKeysPath, string nmsCertificatesPath)
{
// Load KMS private key and certificate
var kmsKeyPair = LoadKeyPairFromPem(kmsKeysPath, "kms_private_key.pem");
var kmsCert = LoadCertificateFromPem(kmsKeysPath, "kms_certificate.pem");

// Generate NMS key pair
var nmsKeyPair = GenerateRsaKeyPair(2048);

// Generate NMS certificate signed by KMS
var nmsCert = GenerateCertificateSignedByKms(nmsKeyPair, kmsKeyPair, kmsCert, "CN=NMS Certificate");

// Save NMS private key and certificate in PEM format
File.WriteAllText(Path.Combine(nmsCertificatesPath, "nms_private_key.pem"), ExportPrivateKeyToPem(nmsKeyPair));
File.WriteAllText(Path.Combine(nmsCertificatesPath, "nms_certificate.pem"), ExportCertificateToPem(nmsCert));

// Export the public key from the NMS certificate
File.WriteAllText(Path.Combine(nmsCertificatesPath, "nms_public_key.pem"), ExportPublicKeyToPem(nmsKeyPair));

Console.WriteLine("NMS Certificate and Private Key saved successfully.");
}

private static AsymmetricCipherKeyPair GenerateRsaKeyPair(int keySize)
{
var keyGen = new RsaKeyPairGenerator();
keyGen.Init(new KeyGenerationParameters(new SecureRandom(), keySize));
return keyGen.GenerateKeyPair();
}

private static Org.BouncyCastle.X509.X509Certificate GenerateSelfSignedCertificate(AsymmetricCipherKeyPair keyPair, string subjectName)
{
var certGen = new X509V3CertificateGenerator();

var secureRandom = new SecureRandom();
certGen.SetSerialNumber(BigInteger.ProbablePrime(120, secureRandom));
certGen.SetIssuerDN(new X509Name(subjectName));
certGen.SetSubjectDN(new X509Name(subjectName));
certGen.SetNotBefore(DateTime.UtcNow);
certGen.SetNotAfter(DateTime.UtcNow.AddYears(5));
certGen.SetPublicKey(keyPair.Public);

// Use a signature factory to sign the certificate
var signatureFactory = new Asn1SignatureFactory("SHA256WithRSA", keyPair.Private, secureRandom);
return certGen.Generate(signatureFactory);
}

private static Org.BouncyCastle.X509.X509Certificate GenerateCertificateSignedByKms(AsymmetricCipherKeyPair nmsKeyPair, AsymmetricCipherKeyPair kmsKeyPair, Org.BouncyCastle.X509.X509Certificate kmsCert, string subjectName)
{
var certGen = new X509V3CertificateGenerator();

var secureRandom = new SecureRandom();
certGen.SetSerialNumber(BigInteger.ProbablePrime(120, secureRandom));
certGen.SetIssuerDN(kmsCert.IssuerDN);
certGen.SetSubjectDN(new X509Name(subjectName));
certGen.SetNotBefore(DateTime.UtcNow);
certGen.SetNotAfter(DateTime.UtcNow.AddYears(5));
certGen.SetPublicKey(nmsKeyPair.Public);

// Use a signature factory to sign the certificate with the KMS private key
var signatureFactory = new Asn1SignatureFactory("SHA256WithRSA", kmsKeyPair.Private, secureRandom);
return certGen.Generate(signatureFactory);
}

private static string ExportPrivateKeyToPem(AsymmetricCipherKeyPair keyPair)
{
using (var stringWriter = new StringWriter())
{
var pemWriter = new PemWriter(stringWriter);
pemWriter.WriteObject(keyPair.Private);
pemWriter.Writer.Flush();
return stringWriter.ToString();
}
}

private static string ExportPublicKeyToPem(AsymmetricCipherKeyPair keyPair)
{
using (var stringWriter = new StringWriter())
{
var pemWriter = new PemWriter(stringWriter);
pemWriter.WriteObject(keyPair.Public); // Exporting the public key instead of the private key
pemWriter.Writer.Flush();
return stringWriter.ToString();
}
}

private static string ExportCertificateToPem(Org.BouncyCastle.X509.X509Certificate cert)
{
using (var stringWriter = new StringWriter())
{
var pemWriter = new PemWriter(stringWriter);
pemWriter.WriteObject(cert);
pemWriter.Writer.Flush();
return stringWriter.ToString();
}
}

private static AsymmetricCipherKeyPair LoadKeyPairFromPem(string path, string privateKeyFileName)
{
using (var reader = new StreamReader(Path.Combine(path, privateKeyFileName)))
{
var pemReader = new PemReader(reader);
return (AsymmetricCipherKeyPair)pemReader.ReadObject();
}
}

private static Org.BouncyCastle.X509.X509Certificate LoadCertificateFromPem(string path, string certificateFileName)
{
using (var reader = new StreamReader(Path.Combine(path, certificateFileName)))
{
var pemReader = new PemReader(reader);
return (Org.BouncyCastle.X509.X509Certificate)pemReader.ReadObject();
}
}

public static void StartTlsServer()
{
try
{
int port = int.Parse(ConfigurationManager.AppSettings["Port"]);
string kmsKeysPath = ConfigurationManager.AppSettings["KmsKeysPath"];
string nmsCertificatesPath = ConfigurationManager.AppSettings["NmsCertificatesPath"];

if (string.IsNullOrEmpty(kmsKeysPath) || string.IsNullOrEmpty(nmsCertificatesPath))
{
throw new ArgumentNullException("One or more configuration settings are missing or empty.");
}

// Load the KMS certificate and private key from PEM files
X509Certificate2 serverCertificate = LoadServerCertificateFromPem(kmsKeysPath);

TcpListener listener = new TcpListener(IPAddress.Any, port);
listener.Start();
Console.WriteLine($"Server started on port {port}");

while (true)
{
TcpClient client = listener.AcceptTcpClient();
SslStream sslStream = new SslStream(client.GetStream(), false, new RemoteCertificateValidationCallback(ValidateClientCertificate), null);
try
{
// Authenticate the client
sslStream.AuthenticateAsServer(serverCertificate, true, System.Security.Authentication.SslProtocols.Tls12, true);
Console.WriteLine("Client connected and authenticated.");

// Handle further interaction with the client
// Here the server reads and validates the client certificate, sends the response
// ...
}
catch (Exception ex)
{
Console.WriteLine($"Exception: {ex.Message}");
}
finally
{
sslStream.Close();
client.Close();
}
}
}
catch (Exception ex)
{
Console.WriteLine($"Exception during server start: {ex.Message}");
}
}

private static X509Certificate2 LoadServerCertificateFromPem(string kmsKeysPath)
{
string certFile = Path.Combine(kmsKeysPath, "kms_certificate.pem");
string privateKeyFile = Path.Combine(kmsKeysPath, "kms_private_key.pem");

if (File.Exists(certFile) && File.Exists(privateKeyFile))
{
try
{
using (var certReader = new StreamReader(certFile))
using (var keyReader = new StreamReader(privateKeyFile))
{
var pemReader = new PemReader(certReader);
var certObject = pemReader.ReadObject() as Org.BouncyCastle.X509.X509Certificate;

pemReader = new PemReader(keyReader);
var keyObject = pemReader.ReadObject() as AsymmetricCipherKeyPair;

var cert = new X509Certificate2(DotNetUtilities.ToX509Certificate(certObject));
var rsa = DotNetUtilities.ToRSA(keyObject.Private as RsaPrivateCrtKeyParameters);

Console.WriteLine("Successfully loaded certificate and private key.");
return cert.CopyWithPrivateKey(rsa);
}
}
catch (Exception ex)
{
Console.WriteLine($"Exception while loading certificate and private key: {ex.Message}");
}
}

throw new FileNotFoundException("No matching certificate and private key pair found.");
}

private static bool ValidateClientCertificate(object sender, System.Security.Cryptography.X509Certificates.X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
if (sslPolicyErrors == SslPolicyErrors.None)
return true;

if (sslPolicyErrors.HasFlag(SslPolicyErrors.RemoteCertificateChainErrors))
{
// Load the KMS public key
var kmsKeysPath = ConfigurationManager.AppSettings["KmsKeysPath"];
var kmsPublicKey = LoadPublicKeyFromPem(kmsKeysPath);

// Convert the client certificate to BouncyCastle format
var clientCert = DotNetUtilities.FromX509Certificate(new X509Certificate2(certificate));

try
{
// Verify the client certificate using the KMS public key
clientCert.Verify(kmsPublicKey);
Console.WriteLine("Client certificate verified successfully.");
return true;
}
catch (Exception ex)
{
Console.WriteLine($"Client certificate verification failed: {ex.Message}");
}
}

return false;
}

private static AsymmetricKeyParameter LoadPublicKeyFromPem(string kmsKeysPath)
{
string publicKeyFile = Path.Combine(kmsKeysPath, "kms_public_key.pem");
using (var reader = new StreamReader(publicKeyFile))
{
var pemReader = new PemReader(reader);
return (AsymmetricKeyParameter)pemReader.ReadObject();
}
}
}

}

Код на стороне клиента
`
using System;
using System.IO;
using System.Net.Sockets;
using System.Security.Cryptography.X509Certificates;
using System.Net.Security;
using System.Configuration;
using System.Threading;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Security;
using BouncyCastleX509Certificate = Org.BouncyCastle.X509.X509Certificate;

namespace NmsClientApp
{
public class NmsClient
{
public static void ConnectToKms()
{
// Configuration parameters
string serverAddress = ConfigurationManager.AppSettings\["ServerAddress"\];
int port = int.Parse(ConfigurationManager.AppSettings\["Port"\]);
string pemDirectory = ConfigurationManager.AppSettings\["PemDirectory"\];
int retryInterval = int.Parse(ConfigurationManager.AppSettings\["RetryInterval"\]); // Retry interval from config (in ms)

while (true)
{
try
{
// Retrieve all PEM files in the specified directory
string[] pemFiles = Directory.GetFiles(pemDirectory, "*.pem");
if (pemFiles.Length == 0)
{
throw new FileNotFoundException("No PEM files found in the specified directory.");
}

foreach (string pemFile in pemFiles)
{
Console.WriteLine($"Processing PEM file: {pemFile}");

// Load the client certificate from the PEM file
X509Certificate2 clientCertificate = LoadCertificateFromPem(pemFile);

// Create a TCP client and establish a connection to the server
Console.WriteLine($"Connecting to KMS server at {serverAddress}:{port}...");
using (TcpClient client = new TcpClient(serverAddress, port))
{
SslStream sslStream = new SslStream(client.GetStream(), false, null);
try
{
// Authenticate SSL/TLS connection
sslStream.AuthenticateAsClient(serverAddress, new X509CertificateCollection { clientCertificate }, System.Security.Authentication.SslProtocols.Tls12, false);
Console.WriteLine("SSL/TLS authentication completed.");

// Read the request from the KMS server
Console.WriteLine("Reading request from KMS server...");
byte[] buffer = new byte[4096];
int bytesRead = sslStream.Read(buffer, 0, buffer.Length);
string requestMessage = System.Text.Encoding.UTF8.GetString(buffer, 0, bytesRead);
Console.WriteLine($"Received request: {requestMessage}");

// Respond to the server's request
if (requestMessage == "Send NMS Certificate")
{
// Send the NMS certificate to the KMS server
Console.WriteLine("Sending NMS certificate...");
byte[] certBytes = clientCertificate.Export(X509ContentType.Cert);
sslStream.Write(certBytes, 0, certBytes.Length);
sslStream.Flush();
Console.WriteLine("Sent NMS certificate.");
}

// Read the server's response
Console.WriteLine("Reading response from KMS server...");
bytesRead = sslStream.Read(buffer, 0, buffer.Length);
string responseMessage = System.Text.Encoding.UTF8.GetString(buffer, 0, bytesRead);
Console.WriteLine($"Response from KMS server: {responseMessage}");

// Exit the loop if connection and communication are successful
break;
}
catch (Exception ex)
{
Console.WriteLine($"SSL/TLS authentication failed: {ex.Message}");
throw;
}
finally
{
sslStream.Close();
client.Close();
}
}
}
}
catch (Exception ex)
{
Console.WriteLine($"Exception: {ex.Message}");
Console.WriteLine(ex.StackTrace);
Console.WriteLine($"Retrying in {retryInterval / 1000} seconds...");
Thread.Sleep(retryInterval);
}
}
}

// Load the certificate from the PEM file
private static X509Certificate2 LoadCertificateFromPem(string pemFilePath)
{
try
{
if (!File.Exists(pemFilePath))
{
throw new FileNotFoundException($"PEM file not found: {pemFilePath}");
}

var certParser = new Org.BouncyCastle.X509.X509CertificateParser();
BouncyCastleX509Certificate cert = certParser.ReadCertificate(File.ReadAllBytes(pemFilePath));

var x509Certificate = new X509Certificate2(cert.GetEncoded());

return x509Certificate;
}
catch (Exception ex)
{
Console.WriteLine($"Error loading certificate: {ex.Message}");
throw;
}
}
}

class Program
{
static void Main(string[] args)
{
// Call the ConnectToKms method to initiate the connection process
NmsClient.ConnectToKms();
}
}

}


Подробнее здесь: https://stackoverflow.com/questions/793 ... ncy-castle
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «C#»