J'ai un écouteur de socket multi-threaded. Il écoute sur un port. Il reçoit des données des sites Web HTTP et envoie une réponse en fonction de leur demande. Cela fonctionne bien. Maintenant, je veux faire la même chose avec un site Web HTTPS. Donc je l'ai changé pour pouvoir lire et écrire via SslStream au lieu de socket.Comment appliquer le fichier de certificat PFX à l'écouteur de socket SslStream?
Le propriétaire du site Web m'a donné un fichier pfx et un mot de passe. Je l'ai placé dans la liste des certificats de confiance de mon magasin de certification local.
Le fichier de certification est récupéré du magasin avec succès. Mais après avoir appelé la méthode AuthenticateAsServer, mon socket de gestionnaire semble être vide. Je ne vois donc pas de données dans la méthode ReceiveCallBack. Comment appliquer un certificat pfx à mon socket SslStream?
Voici mon code:
using System;
using System.Net;
using System.Net.Sockets;
using System.Net.Security;
using System.Threading;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.IO;
namespace SslStreamTestApp
{
public class SslStreamSocketListener
{
private static readonly ManualResetEvent _manualResetEvent = new ManualResetEvent(false);
private readonly string pfxSerialNumber = "12345BLABLABLA";
X509Certificate _cert = null;
private void GetCertificate()
{
X509Store store = new X509Store(StoreName.Root, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly);
X509Certificate2Collection certificateCollection = store.Certificates.Find(X509FindType.FindBySerialNumber, pfxSerialNumber, true);
if (certificateCollection.Count == 1)
{
_cert = certificateCollection[0];
}
}
private void StartListening()
{
GetCertificate();
IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, 9002);
if (localEndPoint != null)
{
Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
if (listener != null)
{
listener.Bind(localEndPoint);
listener.Listen(5);
Console.WriteLine("Socket listener is running...");
listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
}
}
}
private void AcceptCallback(IAsyncResult ar)
{
_manualResetEvent.Set();
Socket listener = (Socket)ar.AsyncState;
Socket handler = listener.EndAccept(ar);
SslStream stream = new SslStream(new NetworkStream(handler, true));
stream.AuthenticateAsServer(_cert, false, System.Security.Authentication.SslProtocols.Ssl3, true);
StateObject state = new StateObject();
state.workStream = stream;
stream.BeginRead(state.buffer, 0, StateObject.BufferSize, ReceiveCallback, state);
listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
}
private void ReceiveCallback(IAsyncResult result)
{
StateObject state = (StateObject)result.AsyncState;
SslStream stream = state.workStream;
// Check how many bytes received
int byteCount = stream.EndRead(result);
Decoder decoder = Encoding.UTF8.GetDecoder();
char[] chars = new char[decoder.GetCharCount(state.buffer, 0, byteCount)];
decoder.GetChars(state.buffer, 0, byteCount, chars, 0);
state.sb.Append(chars);
string check = state.sb.ToString();
if (state.sb.ToString().IndexOf("<EOF>") == -1 && byteCount != 0)
{
// We didn't receive all data. Continue receiving...
stream.BeginRead(state.buffer, 0, state.buffer.Length, new AsyncCallback(ReceiveCallback), stream);
}
else
{
string[] lines = state.sb.ToString().Split('\n');
// send test message to client
byte[] test = Encoding.UTF8.GetBytes("\"infoMessage\":\"test\"");
stream.BeginWrite(test, 0, test.Length, WriteAsyncCallback, stream);
}
}
private void WriteAsyncCallback(IAsyncResult ar)
{
SslStream sslStream = (SslStream)ar.AsyncState;
Console.WriteLine("Sending message to client...");
try
{
sslStream.EndWrite(ar);
}
catch (IOException)
{
Console.WriteLine("Unable to complete send.");
}
finally
{
sslStream.Close();
}
}
}
public class StateObject
{
public SslStream workStream = null;
public const int BufferSize = 1024;
public byte[] buffer = new byte[BufferSize];
public StringBuilder sb = new StringBuilder();
}
}
EDIT: je pense avoir un problème sur la logique SSL. Le fichier PFX appartient au site Web HTTPS. Mais les demandes proviennent de HTTPS à mon écouteur de socket. Ensuite, mon écouteur de socket envoie une réponse. Dans cette situation, suis-je serveur ou client? Est-ce que j'utiliserai AuthenticateAsServer ou AuthenticateAsClient?
Il ne lance pas d'erreur si j'appelle AuthenticateAsServer. Il devient authentifié sans problème. Mais je ne peux pas porter les données dans le socket du gestionnaire à la méthode ReceiveCallBack via le SslStream de mon StateObject.
Y a-t-il une raison pour laquelle vous commencez à recevoir sur le gestionnaire lui-même, et non sur 'SslStream stream'? L'expéditeur envoie très probablement des données cryptées de toute façon. – Caramiriel
Je ne veux pas faire de gros changements dans mon code parce que ça fonctionne bien. Donc, je cherche s'il y a un moyen d'utiliser socket pour HTTPS. –
Je ne suis pas un expert en transport à basse altitude, mais je suppose que c'est impossible.Vous ne pouvez pas vous attendre à lire un socket «brut» et obtenir du texte brut lors de la réception, si le client utilise SSL. Vous aurez besoin de quelque chose pour analyser/décoder le flux SSL (c'est à quoi sert 'SslStream'). Vous pouvez adapter le code existant pour utiliser 'Stream' /' NetworkStream'. Alors 'SslStream' devrait être assez facile. – Caramiriel