Results 1 to 8 of 8

Thread: Passing a Certificate with SSLstream

  1. #1
    .NET Framework
    .NET 4.0
    Join Date
    Nov 2012
    Posts
    144
    Reputation
    77

    Passing a Certificate with SSLstream

    Hey everyone, I'm trying to connect with a service through their EPP server on port 700. The service required me to go out and purchase a certificate. They told me I then had to upload the "public" certificate into my user account (which I did) and then pass the "private" key when making a request to the service. They also claim users tend to pass the public and private keys underneath each other when making a request..

    I'm guessing they are basically taking my private key and comparing it to my public key as an added layer of security? Anyways, I've gone out and tried doing as they said - I took the public key and placed it under the private key and then named the file "FIcert.crt".. It contains nothing other than the two keys inside. I've then tried implementing it into my code:

    Code:
    Dim sslCertificate As X509Certificate2 = New X509Certificate2("C:\Test\FIcert.crt")
    Dim client As New TcpClient(DRShost, 700)
    Dim sslStream As New Security.SslStream(client.GetStream(), False, New RemoteCertificateValidationCallback(AddressOf ValidateServerCertificate), Nothing)
    sslStream.AuthenticateAsClient(sslCertificate.ToString)
    Code:
        Public Shared Function ValidateServerCertificate(ByVal sender As Object, ByVal certificate As X509Certificate, ByVal chain As X509Chain, ByVal sslPolicyErrors As SslPolicyErrors) As Boolean
            If sslPolicyErrors = SslPolicyErrors.None Then Return True
            MsgBox("Certificate error: {0}", sslPolicyErrors)
            Return False
        End Function
    However, I get an error right away on this line:
    Code:
    Dim sslCertificate As X509Certificate2 = New X509Certificate2("C:\Test\FIcert.crt")
    The error is:
    System.Security.Cryptography.CryptographicExceptio n: 'Cannot find the requested object.

    I'm certain the path to the certificate is correct. So, I wonder what other kind of issue this could be related to? Any help or suggestions would be greatly appreciated!

  2. #2
    .NET Framework
    .NET 4.0
    Join Date
    Nov 2012
    Posts
    144
    Reputation
    77
    Just an update, I've also tried changing the location to "C:\\Test\\FIcert.crt" but still receive the same error..

  3. #3
    .NET Framework
    .NET 4.0
    Join Date
    Aug 2004
    Location
    Sydney, Australia
    Posts
    13,998
    Reputation
    1728
    Is there anything remotely useful in the StackTrace or InnerException of the exception?

  4. #4
    .NET Framework
    .NET 4.0
    Join Date
    Nov 2012
    Posts
    144
    Reputation
    77
    Thanks for your reply jmcilhinney! I've done some more searching and made some additional changes..
    First, I found that the CRT file needed to be CER and needed to be converted to DER. I converted my certificate over to DER using a website online and then renamed it from .der to .cer in DOS. I then tried again, but now receive a new error on this line:
    Code:
    Dim client As New TcpClient(DRShost, 700)
    System.Net.Sockets.SocketException: 'A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond'

    I know the hostname I'm using is valid, and so is the port. Also, I'm using an actual hostname here and not an IP address. Could this be happening because I'm not actually passing the newly converted CER certificate properly? Just to refresh, here is my up-to-date code:
    Code:
    Dim sslCertificate As X509Certificate2 = New X509Certificate2("C:\\Test\\FIcert.cer")
    Dim client As New TcpClient(DRShost, 700)
    Dim sslStream As New Security.SslStream(client.GetStream(), False, New RemoteCertificateValidationCallback(AddressOf ValidateServerCertificate), Nothing)
    sslStream.AuthenticateAsClient(sslCertificate.ToString) 'sslStream.AuthenticateAsClient(DRShost, sslCertificate.ToString)
    Code:
    Public Shared Function ValidateServerCertificate(ByVal sender As Object, ByVal certificate As X509Certificate, ByVal chain As X509Chain, ByVal sslPolicyErrors As SslPolicyErrors) As Boolean
        If sslPolicyErrors = SslPolicyErrors.None Then Return True
        MsgBox("Certificate error: {0}", sslPolicyErrors)
        Return False
    End Function

  5. #5
    .NET Framework
    .NET 4.5
    Join Date
    Dec 2005
    Location
    Norway
    Posts
    15,214
    Reputation
    2860
    sslStream.AuthenticateAsClient(sslCertificate.ToSt ring) 'sslStream.AuthenticateAsClient(DRShost, sslCertificate.ToString)
    sslCertificate.ToString as argument is wrong, parameter is 'targetHost', which is one of the DNS names in SAN if present or else the CN in Subject of certificate.

    Dim client As New TcpClient(DRShost, 700)
    Why that fails I don't know, obviously your computer must be able to resolve the DNS name that is in DRShost.
    [xcode=vb] code here [/xcode] - see bbcode list or use formatting buttons in posting editor.

    Visual Studio Community 2017

  6. #6
    .NET Framework
    .NET 4.0
    Join Date
    Nov 2012
    Posts
    144
    Reputation
    77
    Thanks for taking the time to reply JohnH! I've been messing with this more over the last few hours and have gradually made it further and further. Here's an update to where I'm at now..

    First, it appears their firewall had not updated with my whitelisted IP address which was the cause behind the timeout issue that was occurring. I also realized the server will be the one validating the certificate, so I removed the ValidateServerCertificate function and also needed to change around my SSLstream code. I was able to make some changes to that and then began receive this error: The remote certificate is invalid according to the validation procedure

    I felt like I was making some progress now because it seems I am reaching the server and the error now appears to be related to the certificate. Rather than trying to pass the certificate with .ToString in sslStream.AuthenticateAsClient as I did above, I decided to create a collection, store it, and then pass the collection. I also went and changed around it to include the hostname, enableSSLProtocols set to True, and checkCertificateRevocation set to True. Upon making these changes it now seems like I am able to get connected. However, the minute I try to send the first request (A simple Hello request which should return a Welcome response) I get an exception:
    Unable to write data to the transport connection: An established connection was aborted by the software in your host machine.
    This exception actually occurs inside my SendRequest sub (posted below) and specifically on this line:
    Code:
    strm.Write(msgLengthBytes, 0, msgLengthBytes.Length)
    Is there anyway I could tell for sure that I'm connected since I can't even send a Welcome request? I can't seem to figure out why I'm not able to pass this one simple request. Could it be that I shouldn't be encoding in UTF-8? Below now my most up-to-date code:

    Code:
    Dim collection = New X509Certificate2Collection()
    collection.Import("C:\\Test\\FIcert.cer")
    Dim store = New X509Store(StoreName.My, StoreLocation.CurrentUser)
    store.Open(OpenFlags.ReadWrite)
    
    Try
    For Each certificate As X509Certificate2 In collection
    store.Add(certificate)
    Next
    Finally
    store.Close()
    End Try
    
    Dim client As New TcpClient(DRShost, 700)
    Dim sslStream As New Security.SslStream(client.GetStream(), True)
    sslStream.AuthenticateAsClient(DRShost, collection, True, True)
    Dim requestResponse As String = String.Empty
    
    Dim helloElement As XElement = <epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
        <hello/>
    </epp>
    SendRequest(helloElement.ToString, sslStream, System.Text.Encoding.UTF8)
    'Doesn't Get Passed This Point
    requestResponse = GetResponse(sslStream, System.Text.Encoding.UTF8)
    MsgBox(requestResponse)
    and my SendRequest sub:
    Code:
        Private Sub SendRequest(ByVal msg As String, ByVal strm As System.Net.Security.SslStream, ByVal encoding As System.Text.Encoding)
            Dim ret As String = Nothing
            ' get encoded message bytes
            Dim msgBytes As Byte() = encoding.GetBytes(msg)
    
            ' get encoded message length in Big Endian, Windows is Little Endian
            ' this array will be 4 bytes long
            Dim totalMessageLength As Int32 = msgBytes.Length + 4 ' add 4 for the length preface
            Dim msgLengthBytes As Byte() = Int32AsBigEndianBytes(totalMessageLength)
    
            ' write message length
            strm.Write(msgLengthBytes, 0, msgLengthBytes.Length)
    
            ' write message
            strm.Write(msgBytes, 0, msgBytes.Length)
            strm.Flush()
        End Sub

  7. #7
    .NET Framework
    .NET 4.0
    Join Date
    Nov 2012
    Posts
    144
    Reputation
    77
    Just an update..It appears I can get to the exact same spot with the exact same error even when trying a CER file I know will not match the one I have uploaded to the server. So, I'm either still not getting connected, or doing something else wrong. But, it doesn't appear the spot I'm at now has anything to do with the encoding..

  8. #8
    .NET Framework
    .NET 4.0
    Join Date
    Nov 2012
    Posts
    144
    Reputation
    77
    Still been messing with this. After speaking to one of their support guys and doing a bit more research online, I think I've made some more progress. However, the response I get is still blank..

    I previously mentioned the CRT and KEY files needed to be together. I was taking these and trying to make a CER file with them, but apparently they need to be combined into a PFX file. At least, that's about the only way I've found to "combine" these two together. So basically, the CRT file goes in my account on their website, and then I combine the CRT and KEY into one PFX file and pass that with the password. Since I don't have OpenSSL installed I went out and used the same online converter I was using before, only to make the PFX this time. I was able to successfully select my CRT and KEY files and combine them with a password to make one PFX file.

    Below is my most up-to-date code. Maybe @JohnH, @jmcilhinney or someone has an idea as to why I would still be getting a blank response? At this point nothing breaks between making a connection, calling SendRequest and then calling GetResponse. It's not until I try to read the response with an "If" statement that I now get an exception..

    Code:
            Dim collection = New X509Certificate2Collection()
            collection.Import("C:\\Test\\FIcert.pfx", "password", X509KeyStorageFlags.DefaultKeySet)
            Dim store = New X509Store(StoreName.My, StoreLocation.CurrentUser)
            store.Open(OpenFlags.ReadWrite)
    
            Try
                For Each certificate As X509Certificate2 In collection
                    store.Add(certificate)
                Next
            Finally
                store.Close()
            End Try
    
            Dim requestResponse As String = String.Empty
            Dim client As New TcpClient(DRShost, 700)
            Dim sslStream As New Security.SslStream(client.GetStream(), True)
            sslStream.AuthenticateAsClient(DRShost, collection, System.Security.Authentication.SslProtocols.[Default], False)
    
            If client.Connected Then
                Dim helloElement As XElement = <epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
                                                   <hello/>
                                               </epp>
                SendRequest(helloElement.ToString, sslStream, System.Text.Encoding.UTF8)
                requestResponse = GetResponse(sslStream, System.Text.Encoding.UTF8)
    
                If requestResponse.ToLower.Contains("<greeting>") = True Then
        ''''''IT NEVER MAKES IT PAST THIS POINT''''''
                    MsgBox("Success!")
                Else
                    MsgBox("Failed!")
                End If
            Else
                MsgBox("Client not connected!")
                e.Cancel = True
                Exit Sub
            End If
    The specific line I am receiving an exception on now is here:
    Code:
    If requestResponse.ToLower.Contains("<greeting>") = True Then
    and here is the exception
    'Object reference not set to an instance of an object.'
    Could it be something related to X509KeyStorageFlags.DefaultKeySet? Or maybe System.Security.Authentication.SslProtocols.[Default] in my sslStream.AuthenticateAsClient? After speaking with their support guy I can now confirm I definitely have the right certificate on the server, and I appear to be combining the CRT and KEY files properly (it won't let you merge these two files if the keys don't match up). Just can't figure out why I'm still not getting the response!!


    Also, below are my SendRequest and GetResponse subs/functions:

    SendRequest
    Code:
        Private Sub SendRequest(ByVal msg As String, ByVal strm As System.Net.Security.SslStream, ByVal encoding As System.Text.Encoding)
            Dim ret As String = Nothing
            ' get encoded message bytes
            Dim msgBytes As Byte() = encoding.GetBytes(msg)
    
            ' get encoded message length in Big Endian, Windows is Little Endian
            ' this array will be 4 bytes long
            Dim totalMessageLength As Int32 = msgBytes.Length + 4 ' add 4 for the length preface
            Dim msgLengthBytes As Byte() = Int32AsBigEndianBytes(totalMessageLength)
    
            ' write message length
            strm.Write(msgLengthBytes, 0, msgLengthBytes.Length)
    
            ' write message
            strm.Write(msgBytes, 0, msgBytes.Length)
            strm.Flush()
        End Sub
    GetResponse
    Code:
        Private Function GetResponse(ByVal strm As System.Net.Security.SslStream, ByVal encoding As System.Text.Encoding) As String
            Dim ret As String = Nothing
            Try
                ' get encoded response length in Big Endian, Windows is Little Endian
                ' this array will be 4 bytes long
                Dim msgLengthBytes(0 To 3) As Byte
                Dim readBytes As Int32 = strm.Read(msgLengthBytes, 0, 4)
                If readBytes = 4 Then
                    ' should get back 4 bytes that are the BigEndian length
                    Dim totalResponseLength As Int32 = BigEndianInt32BytesToInt32(msgLengthBytes)
                    ' subtract the bytes that comprise the length
                    Dim responseLength As Int32 = totalResponseLength - 4
    
                    ' get encoded message bytes
                    Dim msgBytes(0 To (responseLength - 1)) As Byte
                    readBytes = strm.Read(msgBytes, 0, responseLength)
                    ret = encoding.GetString(msgBytes)
                End If
                Return ret
            Catch ex As Exception
                Return ret
            End Try
        End Function
    Int32AsBigEndianBytes
    Code:
        Private Function Int32AsBigEndianBytes(ByVal val As Int32) As Byte()
            Dim bytes As Byte() = BitConverter.GetBytes(val)
            Array.Reverse(bytes)
            Return bytes
        End Function
    BigEndianInt32BytesToInt32
    Code:
        Private Function BigEndianInt32BytesToInt32(ByVal bytes As Byte()) As Int32
            Dim tmpBytes(0 To bytes.Length - 1) As Byte
            Array.Copy(bytes, tmpBytes, bytes.Length)
            Array.Reverse(tmpBytes)
            Return BitConverter.ToInt32(tmpBytes, 0)
        End Function

Similar Threads

  1. Question Help with x.509 Certificate and TCPClient/SSLstream
    By digitaldrew in forum Net / Sockets
    Replies: 0
    Last Post: 03-19-2016, 4:25 AM
  2. Question Question Regarding SSLstream and Certificate Error
    By digitaldrew in forum Net / Sockets
    Replies: 1
    Last Post: 03-16-2016, 3:15 AM
  3. Question Client/SSLstream - Waiting for the Response
    By digitaldrew in forum Net / Sockets
    Replies: 1
    Last Post: 01-27-2016, 6:49 AM
  4. How do I use Proxies with Sockets/SSLStream
    By Programmatically in forum Net / Sockets
    Replies: 1
    Last Post: 03-22-2008, 3:22 AM
  5. Replies: 0
    Last Post: 01-10-2007, 3:51 AM

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •