dimanche 28 juin 2015

(c# mono) how to properly use x509certificate2 with chain (CAfile)

I trying to understand why when I create TcpListener server in c# I'm failed to retrive certificate chain from the client ssl connection.

I bought certificate from COMODO with folowing files:

  • Root CA Certificate - AddTrustExternalCARoot.crt
  • Intermediate CA Certificate - COMODORSAAddTrustCA.crt
  • Intermediate CA Certificate - COMODORSADomainValidationSecureServerCA.crt

Then I combined those files into one CAfile:

cat COMODORSADomainValidationSecureServerCA.crt COMODORSAAddTrustCA.crt AddTrustExternalCARoot.crt > cafile.cer

Next I create pfx certificate:

openssl pkcs12 -export -in new_api_coinpip_com.crt -inkey new_api.coinpip.com.key -chain -CAfile api.coinpip.com.bundle -out my-csharp-cert.pfx

And finally I writed simple test server application (SslServer.exe):

using System;
using System.Security.Cryptography.X509Certificates;
using System.Net.Sockets;
using System.Net;
using System.Net.Security;
using System.Security.Authentication;
using System.Text;

namespace SslServer
{
    public class Program
    {
        static int Port = 9097;
        static X509Certificate2 serverCertificate = null;
        // The certificate parameter specifies the name of the file  
        // containing the machine certificate. 
        public static void RunServer(string certificate, string password) 
        {
            serverCertificate = new X509Certificate2 (certificate, password);
            // Create a TCP/IP (IPv4) socket and listen for incoming connections11.
            TcpListener listener = new TcpListener(IPAddress.Any, Port);    
            listener.Start();
            while (true) 
            {
                Console.WriteLine("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 = new SslStream(
                client.GetStream(), false);
            // Authenticate the server but don't require the client to authenticate. 
            try 
            {
                sslStream.AuthenticateAsServer(serverCertificate, 
                    false, SslProtocols.Default, true);

                // Set timeouts for the read and write to 5 seconds.
                sslStream.ReadTimeout = 5000;
                sslStream.WriteTimeout = 5000;
                // Read a message from the client.   
                Console.WriteLine("Waiting for client message...");
                string messageData = ReadMessage(sslStream);
                Console.WriteLine("Received: {0}", messageData);

                // Write a message to the client. 
                byte[] message = Encoding.UTF8.GetBytes("Hello from the server.<EOF>");
                Console.WriteLine("Sending hello message.");
                sslStream.Write(message);
            }
            catch (AuthenticationException e)
            {
                Console.WriteLine("Exception: {0}", e.Message);
                if (e.InnerException != null)
                {
                    Console.WriteLine("Inner exception: {0}", e.InnerException.Message);
                }
                Console.WriteLine ("Authentication failed - closing the connection.");
                sslStream.Close();
                client.Close();
                return;
            }
            catch(Exception e) {
                Console.WriteLine("Exception: {0}", e.Message);
                if (e.InnerException != null)
                {
                    Console.WriteLine("Inner exception: {0}", e.InnerException.Message);
                }
                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.
            byte [] buffer = new byte[2048*2];
            StringBuilder messageData = new 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();
                char[] chars = new 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("<EOF>") != -1)
                {
                    break;
                }
            } while (bytes !=0); 

            return messageData.ToString();
        }


        public static int Main(string[] args)
        {

            RunServer (args [0], args[1]);
            return 0;
        } 
    }

}

And when I trying to launch server by

SslServer.exe /path/to/certificate/my-csharp-cert.pfx SomePassword

I'm unable to see certificate chain (which is include in my-csharp-cert.pfx)

openssl s_client -showcerts -connect api.coinpip.com:9097

CONNECTED(00000003)

depth=0 OU = Domain Control Validated, OU = PositiveSSL, CN = api.coinpip.com
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 OU = Domain Control Validated, OU = PositiveSSL, CN = api.coinpip.com
verify error:num=27:certificate not trusted
verify return:1
depth=0 OU = Domain Control Validated, OU = PositiveSSL, CN = api.coinpip.com
verify error:num=21:unable to verify the first certificate
verify return:1
---
Certificate chain
 0 s:/OU=Domain Control Validated/OU=PositiveSSL/CN=api.coinpip.com
   i:/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Domain Validation Secure Server CA
-----BEGIN CERTIFICATE-----
MIIFUjCCBDqgAwIBAgIRAI5OrBia65sFYOEOPAE+YcYwDQYJKoZIhvcNAQELBQAw
gZAxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO
BgNVBAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9ETyBDQSBMaW1pdGVkMTYwNAYD
VQQDEy1DT01PRE8gUlNBIERvbWFpbiBWYWxpZGF0aW9uIFNlY3VyZSBTZXJ2ZXIg
Q0EwHhcNMTUwNTAzMDAwMDAwWhcNMTYwNTMxMjM1OTU5WjBTMSEwHwYDVQQLExhE
b21haW4gQ29udHJvbCBWYWxpZGF0ZWQxFDASBgNVBAsTC1Bvc2l0aXZlU1NMMRgw
FgYDVQQDEw9hcGkuY29pbnBpcC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
ggEKAoIBAQCtTznUdDXEmB2WMjWZNVL/4nfdqvWvRP8zQFx5rhsCFO+N4fsi+FY7
AAC1Mn4/jb0EDjZkxukyz8xbLmMcskDhgFTXlZlhb/5R5mscn2lwlBXwQpTuvjtX
yIwl8a1Ey6cZHVWcjf5vveCa1crwOd7653EsxY9gXf5UEKzST0qRhMMlF2Be120t
nKyqJSvNi6lNYcIrTg3zWLdHRpitZn8uIyVO0i7aq/cujz0O620K4rYR1QJZ7Cij
5hmdGoWIYMsAL0A0qODw5yEGiUqEEGdtHsYHJTopGoQCP1rOyEhlyhoILnyBUDDT
DgUMwYSFLv4JnfXbR52+LBKd5dDImT0LAgMBAAGjggHhMIIB3TAfBgNVHSMEGDAW
gBSQr2o6lFoL2JDqElZz30O0Oija5zAdBgNVHQ4EFgQUAHGRnlng9W4U9qVPYBdS
nfQAW8owDgYDVR0PAQH/BAQDAgWgMAwGA1UdEwEB/wQCMAAwHQYDVR0lBBYwFAYI
KwYBBQUHAwEGCCsGAQUFBwMCME8GA1UdIARIMEYwOgYLKwYBBAGyMQECAgcwKzAp
BggrBgEFBQcCARYdaHR0cHM6Ly9zZWN1cmUuY29tb2RvLmNvbS9DUFMwCAYGZ4EM
AQIBMFQGA1UdHwRNMEswSaBHoEWGQ2h0dHA6Ly9jcmwuY29tb2RvY2EuY29tL0NP
TU9ET1JTQURvbWFpblZhbGlkYXRpb25TZWN1cmVTZXJ2ZXJDQS5jcmwwgYUGCCsG
AQUFBwEBBHkwdzBPBggrBgEFBQcwAoZDaHR0cDovL2NydC5jb21vZG9jYS5jb20v
Q09NT0RPUlNBRG9tYWluVmFsaWRhdGlvblNlY3VyZVNlcnZlckNBLmNydDAkBggr
BgEFBQcwAYYYaHR0cDovL29jc3AuY29tb2RvY2EuY29tMC8GA1UdEQQoMCaCD2Fw
aS5jb2lucGlwLmNvbYITd3d3LmFwaS5jb2lucGlwLmNvbTANBgkqhkiG9w0BAQsF
AAOCAQEAe3C8VWbVoXiKj406XOZ7FUwQkiLX9wzlF9jgvXDuKSj/U65d6v2uwTma
VjufWUN6yVFWS+M16qZwcH7e3z1tUeYZ6g6+lIv6h0/hNmiSt+ruqlqXX8qZYGEI
PK39C1udd8tcwhxq0ob/JOWUhU8QRjKiQ/WZEVL0Ps55qMap4rYgWviqiDLkhRVA
kneXMmKBXQrmxa+AvQ4S1pTDmOr/BMmnAkDSUkPvd4J4KnAL4m2rM2yTG3FsGzgk
06pWGqOOcALYe1qxz3pQCFsTpltDKIRXXSlsJCW06UHezRgA9umkt/Mst0E6g7Kb
yM6fV9XhEyrnPGWstjultuD6BQuO2w==
-----END CERTIFICATE-----
---
Server certificate
subject=/OU=Domain Control Validated/OU=PositiveSSL/CN=api.coinpip.com
issuer=/C=GB/ST=Greater Manchester/L=Salford/O=COMODO CA Limited/CN=COMODO RSA Domain Validation Secure Server CA
---
No client certificate CA names sent
---
SSL handshake has read 1496 bytes and written 621 bytes
---
New, TLSv1/SSLv3, Cipher is AES256-SHA
Server public key is 2048 bit
Secure Renegotiation IS NOT supported
Compression: NONE
Expansion: NONE
SSL-Session:
    Protocol  : TLSv1
    Cipher    : AES256-SHA
    Session-ID: 
    Session-ID-ctx: 
    Master-Key: CE5BF190BCE388CC09ACD846357ECFFED77992C2059A489C8406EAE1CF7A8274B04FF6838DA8182539205331F0F680BE
    Key-Arg   : None
    PSK identity: None
    PSK identity hint: None
    SRP username: None
    Start Time: 1435488120
    Timeout   : 300 (sec)
    Verify return code: 21 (unable to verify the first certificate)
---

Why it's not working? What I missed?

If use same chain cafile.cer for apache there no any problem:

openssl s_client -showcerts -connect api.coinpip.com:443

CONNECTED(00000003)

depth=0 C = SG, ST = Some-State, L = Singapore, O = Internet Widgits Pty Ltd, OU = eztopay.me, CN = eztopay.me, emailAddress = admin@eztopay.me verify error:num=18:self signed certificate verify return:1 depth=0 C = SG, ST = Some-State, L = Singapore, O = Internet Widgits Pty Ltd, OU = eztopay.me, CN = eztopay.me, emailAddress = admin@eztopay.me verify return:1 --- Certificate chain 0 s:/C=SG/ST=Some-State/L=Singapore/O=Internet Widgits Pty Ltd/OU=http://ift.tt/1GTOtaz
i:/C=SG/ST=Some-State/L=Singapore/O=Internet Widgits Pty Ltd/OU=http://ift.tt/1GTOtaz -----BEGIN CERTIFICATE----- MIIEHTCCAwWgAwIBAgIJAPwmQDQj40WhMA0GCSqGSIb3DQEBBQUAMIGkMQswCQYD VQQGEwJTRzETMBEGA1UECAwKU29tZS1TdGF0ZTESMBAGA1UEBwwJU2luZ2Fwb3Jl MSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxEzARBgNVBAsMCmV6 dG9wYXkubWUxEzARBgNVBAMMCmV6dG9wYXkubWUxHzAdBgkqhkiG9w0BCQEWEGFk bWluQGV6dG9wYXkubWUwHhcNMTQwNzE1MDQyMjI2WhcNMTUwNzE1MDQyMjI2WjCB pDELMAkGA1UEBhMCU0cxEzARBgNVBAgMClNvbWUtU3RhdGUxEjAQBgNVBAcMCVNp bmdhcG9yZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRMwEQYD VQQLDAplenRvcGF5Lm1lMRMwEQYDVQQDDAplenRvcGF5Lm1lMR8wHQYJKoZIhvcN AQkBFhBhZG1pbkBlenRvcGF5Lm1lMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB CgKCAQEAuDk+s91Be9I4QuUnAAriSltbgD8VGkQ5D4F0M3KsGgTlTpUTo4LT49eQ Yg7TaialFK9HtCUZcPOo4wTDrFCsP+GJUURxCTkt6LUOnJu4R/VwScx2Rknh18+0 clq5d8UxkMRcEWJ1vdWdn71jjSSBNuVsDJAljKMh1pib26/LoCyskDTBuUE5VOjC Fc8HlHLy4VGAROCarogNgWIhJVeBOZA9f96IutKLinj8Kh6ANh6HXazShatyB7XG AMLbuFFegPcYp/GbKOd/c3k/KWq+PmN+CmIDHqanlv29YGyXVJSnOT4IjEPbNJs3 CE2qK9h/03+fZJfJfasgMWcHSndoBQIDAQABo1AwTjAdBgNVHQ4EFgQU9B3fsjib bsR7VtYr0l7URsdplmswHwYDVR0jBBgwFoAU9B3fsjibbsR7VtYr0l7URsdplmsw DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEABNOdBR+GX1YZDRenTOqN EybA9urdytLjl9jzxqh3jcPQWXNF1v8rg9jTWhIGxnsxXj6igqKHOV6L3MeGt0Vm tlJgdKhTnJPbYVsXVyo12m0DGfd7y2mrqlrAu4/JkMhAgJRdoOC5ShwZm7JQcU8f EvcgyozEmfZwOd3Oj8gZJu8QXF0i5iGfjC34g9tBLvQYu++fbSaRnLYOpHY7rtDZ 3eC+zN3zE2ENtC5leKVOUOM41NNPvHiEYbhXMSqF0TD9+GktW2dU3Np6HvOEif+F /xSCz3PgVtPB97kcGobWQiv1nome5QzkSz814jzKxEYc6qBOrA4GmmnRrOxYe5AA vg== -----END CERTIFICATE----- --- Server certificate subject=/C=SG/ST=Some-State/L=Singapore/O=Internet Widgits Pty Ltd/OU=http://ift.tt/1GTOtaz issuer=/C=SG/ST=Some-State/L=Singapore/O=Internet Widgits Pty Ltd/OU=http://ift.tt/1GTOtaz --- No client certificate CA names sent --- SSL handshake has read 1748 bytes and written 421 bytes --- New, TLSv1/SSLv3, Cipher is ECDHE-RSA-AES256-GCM-SHA384 Server public key is 2048 bit Secure Renegotiation IS supported Compression: NONE Expansion: NONE SSL-Session: Protocol : TLSv1.2 Cipher : ECDHE-RSA-AES256-GCM-SHA384 Session-ID: CE13742D4BA8B45D899819FF011B9033ACAFD0DCF65CC53E8F35ADDF60D3DDF6 Session-ID-ctx: Master-Key: 5656D423DED4A8D65EFF63080A514A2C3B9D27A8BBB1D39FFB3367484842D8B0300591C7E837B3894A7172AE3458AE21 Key-Arg : None PSK identity: None PSK identity hint: None SRP username: None TLS session ticket lifetime hint: 300 (seconds) TLS session ticket: 0000 - 49 42 9d c0 a1 c6 13 3d-1e 58 3e 08 8a 7e aa 60 IB.....=.X>..~.` 0010 - 66 1f 2f fc b0 3f 9b 0e-97 91 d8 de fc fd 56 33 f./..?........V3 0020 - 94 43 a0 8b 84 a7 b3 67-10 b1 d0 c6 62 af 5d 0f .C.....g....b.]. 0030 - dc 5f 78 e1 9b 68 ed a5-7a 48 98 11 d9 ae ba 71 .x..h..zH.....q 0040 - 2b 84 3a 82 97 ca 1b 44-52 67 09 31 27 4b 36 5b +.:....DRg.1'K6[ 0050 - 91 7b cd b6 78 05 cf e5-ab b4 4c 83 18 46 dc b0 .{..x.....L..F.. 0060 - 9d 09 41 57 ea 4c 05 a2-44 59 89 d9 42 98 97 89 ..AW.L..DY..B... 0070 - 93 9c cc ce db 8d 64 54-30 08 b7 3c 1e 2c b4 94 ......dT0..<.,.. 0080 - 71 90 d3 0e 7f d1 f7 9c-d2 4d 1f 97 65 4f 4a 9e q........M..eOJ. 0090 - 4a c3 f7 67 20 04 41 ca-b7 15 4f 5e 1a ba fd 3c J..g .A...O^...< 00a0 - 1d 34 1f 5f cf 37 93 79-10 1b d5 b0 ab 46 0c 32 .4..7.y.....F.2 00b0 - bd bf 2f 1c 17 b1 52 43-20 e0 2e 0e f9 89 18 29 ../...RC ......)

Start Time: 1435488467
Timeout   : 300 (sec)

Verify return code: 18 (self signed certificate)

Any suggestion how to fix this and make certificate chain works in c#?

Aucun commentaire:

Enregistrer un commentaire