Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Visual Studio Discussion :

Serveur TCP sécurisé


Sujet :

Visual Studio

  1. #1
    Futur Membre du Club
    Serveur TCP sécurisé
    Bonjour à tous,

    Je voudrais développer un serveur TCP sécurisé avec un certificat SSL. L’objectif de ce serveur sera plus tard d’être interrogé par une application web via WebSocket (https://www.tutorialspoint.com/webso...er_working.htm) en wss (vu que l’application est en HTTPS). J’ai donc, pour commencer, pris l’exemple disponible sur la documentation officielle de Microsoft (https://docs.microsoft.com/fr-fr/dot...ew=netcore-3.1) et j’ai généré des certificats de deux manières différentes : un avec OpenSSL et l’autre avec PowerShell for VS. J’ai ensuite essayé d’utiliser les certificats dans l’exemple fourni par Microsoft, mais je n’y arrive pas, peut-être que ce n’est pas comme cela que ça fonctionne ? Peut être que les certificats générés ne sont pas bons ? J’ai fais pas mal de recherche sur internet et je n’ai rien trouvé de vraiment concluant à ce sujet.

    Commandes utilisées pour générer le certificat avec PowerShell for VS :

    makecert -r -pe -n "CN=localhost" -sky exchange -sv server.pvk server.cer
    pvk2pfx -pvk server.pvk -spc server.cer -pfx server.pfx


    Code c++-cli :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    #using <System.dll>
    #include "pch.h"
    
    using namespace System;
    using namespace System::Collections;
    using namespace System::Net;
    using namespace System::Net::Sockets;
    using namespace System::Net::Security;
    using namespace System::Security::Authentication;
    using namespace System::Text;
    using namespace System::Security::Cryptography::X509Certificates;
    using namespace System::IO;
    
    public ref class SslTcpServer sealed
    {
    private:
        static X509Certificate^ serverCertificate = gcnew X509Certificate("server.cer","1234567890");
    
    public:
    
        // The certificate parameter specifies the name of the file 
        // containing the machine certificate.
        static void RunServer(String^ certificate)
        {
            serverCertificate = X509Certificate::CreateFromCertFile(certificate);
    
            IPAddress^ localAddr;
    
            // Create a TCP/IP (IPv4) socket and listen for incoming connections.
            TcpListener^ listener = gcnew TcpListener(localAddr, 8080);
            listener->Start();
    
            while (true)
            {
                Console::WriteLine(L"Waiting for a client to connect...");
    
                // Application blocks while waiting for an incoming connection.
                // Type CNTL-C to terminate the server.
                TcpClient^ client = listener->AcceptTcpClient();
                ProcessClient(client);
    
            }
        }
    
    
        static void ProcessClient(TcpClient^ client)
        {
    
            // A client has connected. Create the 
            // SslStream using the client's network stream.
            SslStream^ sslStream = gcnew SslStream(client->GetStream(), false);
    
            // Authenticate the server but don't require the client to authenticate.
            try
            {
                sslStream->AuthenticateAsServer(serverCertificate, false, true);
                // false == no client cert required; true == check cert revocation.
    
                // Display the properties and settings for the authenticated stream.
                DisplaySecurityLevel(sslStream);
                DisplaySecurityServices(sslStream);
                DisplayCertificateInformation(sslStream);
                DisplayStreamProperties(sslStream);
    
                // Set timeouts for the read and write to 5 seconds.
                sslStream->ReadTimeout = 5000;
                sslStream->WriteTimeout = 5000;
    
                // Read a message from the client.   
                Console::WriteLine(L"Waiting for client message...");
                String^ messageData = ReadMessage(sslStream);
                Console::WriteLine(L"Received: {0}", messageData);
    
                // Write a message to the client.
                array<Byte>^ message = Encoding::UTF8->GetBytes(L"Hello from the server.<EOF>");
                Console::WriteLine(L"Sending hello message.");
                sslStream->Write(message);
            }
            catch (AuthenticationException^ e)
            {
                Console::WriteLine(L"Exception: {0}", e->Message);
                if (e->InnerException != nullptr)
                {
                    Console::WriteLine(L"Inner exception: {0}", e->InnerException->Message);
                }
                Console::WriteLine(L"Authentication failed - closing the connection.");
                sslStream->Close();
                client->Close();
                return;
            }
            finally
            {
    
                // The client stream will be closed with the sslStream
                // because we specified this behavior when creating
                // the sslStream.
                sslStream->Close();
                client->Close();
            }
    
        }
    
    
        static String^ ReadMessage(SslStream^ sslStream)
        {
    
            // Read the  message sent by the client.
            // The client signals the end of the message using the
            // "<EOF>" marker.
            array<Byte>^ buffer = gcnew array<Byte>(2048);
            StringBuilder^ messageData = gcnew StringBuilder;
            int bytes = -1;
            do
            {
    
                // Read the client's test message.
                bytes = sslStream->Read(buffer, 0, buffer->Length);
    
                // Use Decoder class to convert from bytes to UTF8
                // in case a character spans two buffers.
                Decoder^ decoder = Encoding::UTF8->GetDecoder();
                array<Char>^ chars = gcnew array<Char>(decoder->GetCharCount(buffer, 0, bytes));
                decoder->GetChars(buffer, 0, bytes, chars, 0);
                messageData->Append(chars);
    
                // Check for EOF or an empty message.
                if (messageData->ToString()->IndexOf(L"<EOF>") != -1)
                {
                    break;
                }
            } while (bytes != 0);
    
            return messageData->ToString();
        }
    
    
        static void DisplaySecurityLevel(SslStream^ stream)
        {
            Console::WriteLine(L"Cipher: {0} strength {1}", stream->CipherAlgorithm, stream->CipherStrength);
            Console::WriteLine(L"Hash: {0} strength {1}", stream->HashAlgorithm, stream->HashStrength);
            Console::WriteLine(L"Key exchange: {0} strength {1}", stream->KeyExchangeAlgorithm, stream->KeyExchangeStrength);
            Console::WriteLine(L"Protocol: {0}", stream->SslProtocol);
        }
    
    
        static void DisplaySecurityServices(SslStream^ stream)
        {
            Console::WriteLine(L"Is authenticated: {0} as server? {1}", stream->IsAuthenticated, stream->IsServer);
            Console::WriteLine(L"IsSigned: {0}", stream->IsSigned);
            Console::WriteLine(L"Is Encrypted: {0}", stream->IsEncrypted);
        }
    
    
        static void DisplayStreamProperties(SslStream^ stream)
        {
            Console::WriteLine(L"Can read: {0}, write {1}", stream->CanRead, stream->CanWrite);
            Console::WriteLine(L"Can timeout: {0}", stream->CanTimeout);
        }
    
    
        static void DisplayCertificateInformation(SslStream^ stream)
        {
            Console::WriteLine(L"Certificate revocation list checked: {0}", stream->CheckCertRevocationStatus);
            X509Certificate^ localCertificate = stream->LocalCertificate;
            if (stream->LocalCertificate != nullptr)
            {
                Console::WriteLine(L"Local cert was issued to {0} and is valid from {1} until {2}.",
                    localCertificate->Subject,
                    localCertificate->GetEffectiveDateString(),
                    localCertificate->GetExpirationDateString());
            }
            else
            {
                Console::WriteLine(L"Local certificate is null.");
            }
    
            X509Certificate^ remoteCertificate = stream->RemoteCertificate;
            if (stream->RemoteCertificate != nullptr)
            {
                Console::WriteLine(L"Remote cert was issued to {0} and is valid from {1} until {2}.",
                    remoteCertificate->Subject,
                    remoteCertificate->GetEffectiveDateString(),
                    remoteCertificate->GetExpirationDateString());
            }
            else
            {
                Console::WriteLine(L"Remote certificate is null.");
            }
        }
    
    
    private:
    
        static void DisplayUsage()
        {
            Console::WriteLine(L"To start the server specify:");
            Console::WriteLine(L"serverSync certificateFile.cer");
            Environment::Exit(1);
        }
    
    public:
        int RunServerASync()
        {
            array<String^>^ args = Environment::GetCommandLineArgs();
            String^ certificate = nullptr;
            if (args == nullptr || args->Length < 2)
            {
                DisplayUsage();
            }
    
            certificate = args[1];
            SslTcpServer::RunServer(certificate);
            return 0;
        }
    
    };
    
    void main() {
        SslTcpServer^ sts = gcnew SslTcpServer();
        sts->RunServerASync();
    }


    En vous remerciant par avance.

  2. #2
    Futur Membre du Club
    J'ai un peu avancé mais maintenant je suis confronté à un autre soucis : je n'arrive pas à fournir les bons paramètres au client afin qu'il puisse se connecter au serveur TCP. Auriez-vous une idée ?







    Code c++-cli :Sélectionner tout -Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    #using <System.dll>
    #using <System.Security.dll>
    #include "pch.h"
    
    using namespace System;
    using namespace System::Collections;
    using namespace System::Globalization;
    using namespace System::Net;
    using namespace System::Net::Security;
    using namespace System::Net::Sockets;
    using namespace System::Security::Authentication;
    using namespace System::Text;
    using namespace System::Security::Cryptography::X509Certificates;
    using namespace System::IO;
    
    namespace NlsClientSync
    {
        public ref class SslTcpClient
        {
        private:
            static Hashtable^ certificateErrors = gcnew Hashtable;
            // Load a table of errors that might cause 
            // the certificate authentication to fail.
            static void InitializeCertificateErrors()
            {
                certificateErrors->Add(0x800B0101,
                    "The certification has expired.");
                certificateErrors->Add(0x800B0104,
                    "A path length constraint "
                    "in the certification chain has been violated.");
                certificateErrors->Add(0x800B0105,
                    "A certificate contains an unknown extension "
                    "that is marked critical.");
                certificateErrors->Add(0x800B0107,
                    "A parent of a given certificate in fact "
                    "did not issue that child certificate.");
                certificateErrors->Add(0x800B0108,
                    "A certificate is missing or has an empty value "
                    "for a necessary field.");
                certificateErrors->Add(0x800B0109,
                    "The certificate root is not trusted.");
                certificateErrors->Add(0x800B010C,
                    "The certificate has been revoked.");
                certificateErrors->Add(0x800B010F,
                    "The name in the certificate does not not match "
                    "the host name requested by the client.");
                certificateErrors->Add(0x800B0111,
                    "The certificate was explicitly marked "
                    "as untrusted by the user.");
                certificateErrors->Add(0x800B0112,
                    "A certification chain processed correctly, "
                    "but one of the CA certificates is not trusted.");
                certificateErrors->Add(0x800B0113,
                    "The certificate has an invalid policy.");
                certificateErrors->Add(0x800B0114,
                    "The certificate name is either not "
                    "in the permitted list or is explicitly excluded.");
                certificateErrors->Add(0x80092012,
                    "The revocation function was unable to check "
                    "revocation for the certificate.");
                certificateErrors->Add(0x80090327,
                    "An unknown error occurred while "
                    "processing the certificate.");
                certificateErrors->Add(0x80096001,
                    "A system-level error occurred "
                    "while verifying trust.");
                certificateErrors->Add(0x80096002,
                    "The certificate for the signer of the message "
                    "is invalid or not found.");
                certificateErrors->Add(0x80096003,
                    "One of the counter signatures was invalid.");
                certificateErrors->Add(0x80096004,
                    "The signature of the certificate "
                    "cannot be verified.");
                certificateErrors->Add(0x80096005,
                    "The time stamp signature or certificate "
                    "could not be verified or is malformed.");
                certificateErrors->Add(0x80096010,
                    "The digital signature of the object "
                    "was not verified.");
                certificateErrors->Add(0x80096019,
                    "The basic constraint extension of a certificate "
                    "has not been observed.");
            }
    
            static String^ CertificateErrorDescription(UInt32 problem)
            {
                // Initialize the error message dictionary 
                // if it is not yet available.
                if (certificateErrors->Count == 0)
                {
                    InitializeCertificateErrors();
                }
    
                String^ description = safe_cast<String^>(
                    certificateErrors[problem]);
                if (description == nullptr)
                {
                    description = String::Format(
                        CultureInfo::CurrentCulture,
                        "Unknown certificate error - 0x{08}",
                        problem);
                }
    
                return description;
            }
    
        public:
            // The following method is invoked 
            // by the CertificateValidationDelegate.
            static bool ValidateServerCertificate(
                Object^ sender,
                X509Certificate^ certificate,
                X509Chain^ chain,
                SslPolicyErrors sslPolicyErrors)
            {
    
                Console::WriteLine("Validating the server certificate.");
                if (sslPolicyErrors == SslPolicyErrors::None)
                    return true;
    
                Console::WriteLine("Certificate error: {0}", sslPolicyErrors);
    
                // Do not allow this client to communicate with unauthenticated servers.
                return false;
            }
    
            static void RunClient(String^ machineName, String^ serverName)
            {
    
                // Create a TCP/IP client socket.
                // machineName is the host running the server application.
                TcpClient^ client = gcnew TcpClient(machineName, 8080);
                Console::WriteLine("Client connected.");
    
                // Create an SSL stream that will close 
                // the client's stream.
                SslStream^ sslStream = gcnew SslStream(
                    client->GetStream(), false,
                    gcnew RemoteCertificateValidationCallback(ValidateServerCertificate),
                    nullptr);
    
                // The server name must match the name
                // on the server certificate.
                try
                {
                    sslStream->AuthenticateAsClient(serverName);
                }
                catch (AuthenticationException^ ex)
                {
                    Console::WriteLine("Exception: {0}", ex->Message);
                    if (ex->InnerException != nullptr)
                    {
                        Console::WriteLine("Inner exception: {0}",
                            ex->InnerException->Message);
                    }
    
                    Console::WriteLine("Authentication failed - "
                        "closing the connection.");
                    sslStream->Close();
                    client->Close();
                    return;
                }
                // Encode a test message into a byte array.
                // Signal the end of the message using the "<EOF>".
                array<Byte>^ messsage = Encoding::UTF8->GetBytes(
                    "Hello from the client.<EOF>");
    
                // Send hello message to the server.
                sslStream->Write(messsage);
                sslStream->Flush();
                // Read message from the server.
                String^ serverMessage = ReadMessage(sslStream);
                Console::WriteLine("Server says: {0}", serverMessage);
    
                // Close the client connection.
                sslStream->Close();
                client->Close();
                Console::WriteLine("Client closed.");
            }
        private:
            static String^ ReadMessage(SslStream^ sslStream)
            {
    
                // Read the  message sent by the server.
                // The end of the message is signaled using the
                // "<EOF>" marker.
                array<Byte>^ buffer = gcnew array<Byte>(2048);
                StringBuilder^ messageData = gcnew StringBuilder;
                // Use Decoder class to convert from bytes to UTF8
                // in case a character spans two buffers.
                Encoding^ u8 = Encoding::UTF8;
                Decoder^ decoder = u8->GetDecoder();
    
                int bytes = -1;
                do
                {
                    bytes = sslStream->Read(buffer, 0, buffer->Length);
    
                    array<__wchar_t>^ chars = gcnew array<__wchar_t>(
                        decoder->GetCharCount(buffer, 0, bytes));
                    decoder->GetChars(buffer, 0, bytes, chars, 0);
                    messageData->Append(chars);
    
                    // Check for EOF.
                    if (messageData->ToString()->IndexOf("<EOF>") != -1)
                    {
                        break;
                    }
                } while (bytes != 0);
    
                return messageData->ToString();
            }
        };
    }
    
    int main()
    {
        array<String^>^ args = Environment::GetCommandLineArgs();
        String^ serverCertificateName = nullptr;
        String^ machineName = nullptr;
        /*if (args == nullptr || args->Length < 2)
        {
            Console::WriteLine("To start the client specify:");
            Console::WriteLine("clientSync machineName [serverName]");
            return 1;
        }
    
        // User can specify the machine name and server name.
        // Server name must match the name on 
        // the server's certificate.
        machineName = args[1];
        if (args->Length < 3)
        {
            serverCertificateName = machineName;
        }
        else
        {
            serverCertificateName = args[2];
        };*/
    
        NlsClientSync::SslTcpClient::RunClient("localhost","test.pvk");
    
        return 0;
    }